4. Inheritance Mappings
1. @Inheritance
About
@Inheritanceis an annotation used in JPA to define inheritance mapping strategies between entity classes.It specifies how the inheritance between parent and child entity classes should be mapped into relational database tables.
Why Is It Needed?
In Java, it's natural to use class inheritance for code reuse and modeling hierarchy.
In relational databases, there is no native inheritance — every table is flat.
So JPA must simulate inheritance by deciding how to map the class hierarchy to tables.
Where @Inheritance is Used ?
@Inheritance is Used ?When we have:
A base entity class (abstract or concrete).
Multiple subclasses extending the base.
We want the inheritance relationship persisted properly in DB.
Syntax of @Inheritance
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Parent {
// fields
}strategyis mandatory. It tells JPA which way to map the hierarchy.
Inheritance Strategies in JPA
There are 3 official strategies under @Inheritance(strategy = ...):
SINGLE_TABLE
One table for all classes.
TABLE_PER_CLASS
One table per concrete class.
JOINED
Multiple tables linked by primary keys.
1. InheritanceType.SINGLE_TABLE
All entities in the hierarchy are mapped into a single table.
One big table with columns from parent and child classes.
Discriminator column is used to differentiate which row belongs to which class.
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type")
public class Employee {
@Id
private Long id;
private String name;
}@Entity
@DiscriminatorValue("manager")
public class Manager extends Employee {
private String departmentName;
}@Entity
@DiscriminatorValue("developer")
public class Developer extends Employee {
private String programmingLanguage;
}Database Table
1
John
HR
NULL
manager
2
Jane
NULL
Java
developer
Characteristics
Performance
Fastest (only one table to join).
Schema
Sparse columns (many NULLs if many subclasses).
Flexibility
Hard to add constraints because unrelated fields exist in same table.
Discriminator
Mandatory (@DiscriminatorColumn).
Example use case
Small inheritance hierarchies with few fields.
2. InheritanceType.TABLE_PER_CLASS
Each concrete entity gets its own table.
Each table duplicates the columns inherited from parent.
No need for discriminator column.
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Employee {
@Id
@GeneratedValue
private Long id;
private String name;
}@Entity
public class Manager extends Employee {
private String departmentName;
}@Entity
public class Developer extends Employee {
private String programmingLanguage;
}Database Tables
Separate table for each subclass. Each table will have own copy of inherited fields.
Manager Table
1
John
HR
3
Bob
Finance
Developer Table
2
Jane
Java
Notes:
No NULLs.
Duplicate columns (
id,name) in all tables.Querying across all employees needs a UNION.
Characteristics
Performance
Inserts fast. Queries across hierarchy are slow (UNION needed).
Schema
No NULL fields.
Flexibility
Good if subclasses are quite different.
Discriminator
Not needed.
Example use case
When subclasses are very different and rarely queried together.
3. InheritanceType.JOINED
Parent and child classes have their own tables.
Tables are linked via primary key / foreign key.
Fetching a subclass involves a JOIN.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Employee {
@Id
private Long id;
private String name;
}@Entity
public class Manager extends Employee {
private String departmentName;
}@Entity
public class Developer extends Employee {
private String programmingLanguage;
}Database Tables
One table for base class and one for each subclass. Tables are linked by primary key = foreign key.
Employee Table (base table)
1
John
2
Jane
3
Bob
Manager Table
1
HR
3
Finance
Developer Table
2
Java
Notes:
idis Primary Key and Foreign Key in child tables.Fetching a full Manager/Developer record requires JOIN on
id.Very normalized.
Characteristics
Performance
Slower (needs JOINs on select).
Schema
Normalized (no NULLs).
Flexibility
Best for strict relational modeling.
Discriminator
Optional (can use).
Example use case
When normalized design is required, and JOIN cost is acceptable.
2. @DiscriminatorColumn
About
@DiscriminatorColumn is a JPA annotation used in the context of inheritance mapping in JPA to define a discriminator column. It helps in distinguishing between different entities in the same table when the SINGLE_TABLE or JOINED inheritance strategy is used. This column holds the value that determines which subclass the current row corresponds to.
Why is it Needed?
Inheritance Mapping: When using single-table inheritance, all subclasses are stored in the same table. The discriminator column is used to store the type of entity (i.e., the subclass) for each row.
Class Differentiation: In databases, there's no direct concept of inheritance, so JPA uses the discriminator column to mark which entity a row belongs to.
Performance: The discriminator column avoids using complex joins and makes querying easier and more efficient in the
SINGLE_TABLEstrategy.
Where is @DiscriminatorColumn Used ?
@DiscriminatorColumn Used ?It is used in the parent entity class where inheritance is being mapped.
It works in the context of
SINGLE_TABLEorJOINEDinheritance strategies, where a single table stores all the child entity data (forSINGLE_TABLE) or child entities have their own table but still rely on the base entity table (forJOINED).
Syntax
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "employee_type", discriminatorType = DiscriminatorType.STRING)
public class Employee {
@Id
private Long id;
private String name;
}name: Specifies the name of the discriminator column (e.g.,
employee_typein the example).discriminatorType: Specifies the type of the discriminator column (
STRING,INTEGER,CHAR, etc.). Default isDiscriminatorType.STRING.
How It Works ?
The
@DiscriminatorColumndefines a special column in the table that stores a discriminator value.The value in this column helps JPA determine which class the row belongs to.
@DiscriminatorValueon each subclass specifies the value that will be inserted in the discriminator column for that subclass.
Example Scenario with SINGLE_TABLE Inheritance:
SINGLE_TABLE Inheritance:@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "employee_type", discriminatorType = DiscriminatorType.STRING)
public class Employee {
@Id
private Long id;
private String name;
}
@Entity
@DiscriminatorValue("MANAGER")
public class Manager extends Employee {
private String departmentName;
}
@Entity
@DiscriminatorValue("DEVELOPER")
public class Developer extends Employee {
private String programmingLanguage;
}Database Table Structure (for SINGLE_TABLE strategy):
SINGLE_TABLE strategy):1
John
MANAGER
HR
NULL
2
Alice
DEVELOPER
NULL
Java
3
Bob
DEVELOPER
NULL
Python
Key Characteristics
Purpose
To distinguish between entities when mapped into a single table (or joined strategy).
Discriminator Value
The value in this column helps identify which subclass the row belongs to.
Column Type
Can be STRING, CHAR, INTEGER, etc., depending on the data.
Use Case
Essential for the SINGLE_TABLE inheritance strategy.
Defaults
If not defined, defaults to DTYPE as the column name, and DiscriminatorType.STRING for type.
Inheritance Type
Primarily used in SINGLE_TABLE inheritance, but can also be used in JOINED.
Customizing @DiscriminatorColumn
@DiscriminatorColumnWe can further customize the discriminator column with additional attributes:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
name = "employee_type",
discriminatorType = DiscriminatorType.STRING,
length = 50, // Set the maximum length of the discriminator value
columnDefinition = "VARCHAR(50) NOT NULL" // Custom SQL definition for the column
)
public class Employee {
@Id
private Long id;
private String name;
}Attributes
name: Name of the discriminator column.
discriminatorType: Type of the discriminator value (can be
STRING,INTEGER, etc.).length: Optional. Specifies the maximum length for the discriminator column (default is 31).
columnDefinition: Optional. Allows for specifying the column's SQL definition.
When Not to Use @DiscriminatorColumn
@DiscriminatorColumnPerformance Concerns: The
SINGLE_TABLEstrategy may become inefficient when there are a lot of fields that are not relevant for certain subclasses, leading to sparse tables with manyNULLvalues. In such cases, other strategies likeJOINEDorTABLE_PER_CLASSmay be more efficient.Complex Inheritance: If the hierarchy has many deep or unrelated subclasses, managing the
@DiscriminatorColumncan become difficult, and you might prefer using a different inheritance strategy.
Best Practices
Keep it Simple
Use SINGLE_TABLE and @DiscriminatorColumn for simple hierarchies. Avoid deep inheritance trees.
Column Type
Use DiscriminatorType.STRING for most cases, but if you need a number, use DiscriminatorType.INTEGER or CHAR for efficiency.
Avoid NULLs
If you are using SINGLE_TABLE strategy, consider the schema design and avoid having many NULL columns for subclasses that don't need them.
Customization
Customize the column definition using columnDefinition if you need more control over how the column is created in the database.
Clear Naming
Ensure clear and meaningful values for the discriminator column values using @DiscriminatorValue.
3. @DiscriminatorValue
About
@DiscriminatorValue is a JPA annotation used to specify the value that will be stored in the discriminator column for each subclass of a parent entity when inheritance is mapped using SINGLE_TABLE or JOINED inheritance strategies. The discriminator column (defined by @DiscriminatorColumn) helps JPA differentiate between different subclasses of the same parent entity in the database.
Why is @DiscriminatorValue Needed?
@DiscriminatorValue Needed?Inheritance Strategy: It is crucial for the
SINGLE_TABLEinheritance strategy where all subclasses are stored in the same table. Each subclass needs a discriminator value to tell which entity type the row corresponds to.Entity Type Identification: Without
@DiscriminatorValue, JPA cannot distinguish between different types of entities stored in the same table.Efficient Data Storage: Helps in storing and querying different entity types in the same table, which can improve performance and reduce the need for multiple database tables in certain situations.
Where is @DiscriminatorValue Used?
@DiscriminatorValue Used?It is applied on subclass entities that inherit from a parent entity using a single table inheritance strategy (
SINGLE_TABLEorJOINED).Each subclass must declare a value for
@DiscriminatorValuethat is inserted into the discriminator column when an instance of the subclass is persisted.
Syntax of @DiscriminatorValue
@DiscriminatorValue@Entity
@DiscriminatorValue("SUBCLASS_NAME")
public class Subclass extends ParentClass {
// Class implementation
}@DiscriminatorValue("SUBCLASS_NAME"): Specifies the value that will be stored in the discriminator column for this subclass.
How It Works ?
The
@DiscriminatorValueannotation is applied to subclasses in the inheritance hierarchy.When an instance of the subclass is saved to the database, JPA inserts the corresponding discriminator value into the discriminator column (defined by
@DiscriminatorColumnin the parent entity).JPA uses the value stored in the discriminator column to identify which subclass the row belongs to when querying the data.
Example
Consider a scenario where we have an Employee superclass and two subclasses: Manager and Developer.
Parent Entity
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "employee_type", discriminatorType = DiscriminatorType.STRING)
public class Employee {
@Id
private Long id;
private String name;
// Getter and Setter methods
}Subclass 1: Manager
@Entity
@DiscriminatorValue("MANAGER")
public class Manager extends Employee {
private String departmentName;
// Getter and Setter methods
}Subclass 2: Developer
@Entity
@DiscriminatorValue("DEVELOPER")
public class Developer extends Employee {
private String programmingLanguage;
// Getter and Setter methods
}Database Table Structure (for SINGLE_TABLE strategy)
1
John
MANAGER
HR
NULL
2
Alice
DEVELOPER
NULL
Java
3
Bob
DEVELOPER
NULL
Python
In this case:
The
employee_typecolumn is the discriminator column.The value
"MANAGER"is inserted for theManagersubclass, and"DEVELOPER"for theDevelopersubclass.
Characteristics of @DiscriminatorValue
@DiscriminatorValuePurpose
Specifies the value that will be stored in the discriminator column for a specific subclass.
Target
Applied to subclasses in an inheritance hierarchy.
Inheritance Strategy
Primarily used in the SINGLE_TABLE inheritance strategy. It can also be used in JOINED.
Discriminator Column
The value is inserted into the column defined by @DiscriminatorColumn.
Value Type
The value can be a string, integer, or other simple types, based on the discriminator column type.
Role
Helps JPA identify which subclass the row in the table represents.
Required
Yes, each subclass in a SINGLE_TABLE inheritance strategy must declare a discriminator value.
Default Behavior of @DiscriminatorValue
@DiscriminatorValueIf @DiscriminatorValue is not specified on a subclass, JPA will use the class name (converted to a string) as the discriminator value by default.
Example (Implicit Default):
@Entity
@DiscriminatorValue("MANAGER")
public class Manager extends Employee {
private String departmentName;
}If @DiscriminatorValue were omitted, the discriminator value for Manager would be automatically set to "Manager", which is the name of the class.
Customizing @DiscriminatorValue
@DiscriminatorValueWe can customize the discriminator values to make them more readable and relevant to the domain model.
@Entity
@DiscriminatorValue("HR_MANAGER")
public class HRManager extends Manager {
private String region;
// Getter and Setter methods
}In this case, the value "HR_MANAGER" will be used for rows representing HRManager in the discriminator column.
When Not to Use @DiscriminatorValue
@DiscriminatorValueComplex Relationships: When the inheritance hierarchy involves complex relationships, consider using the
JOINEDstrategy instead, which splits each class into its own table.Multiple Inheritance: If the entity hierarchy is deep with many unrelated subclasses, the
SINGLE_TABLEstrategy might become inefficient because of the large number ofNULLvalues in the columns.
Last updated