JPA Inheritance Mapping Strategies
Fast recall
Quick revision
Core answer
ORM design skills — knowledge of DB schema implications and performance trade-offs of each inheritance strategy
Defaulting to SINGLE_TABLE without realizing every subclass-specific column becomes nullable — violates NOT NULL invariants at the DB level
Discuss how polymorphic queries differ per strategy (JOINED does LEFT JOIN to all subtables, SINGLE_TABLE filters on discriminator), and how `@MappedSuperclass` differs from `@Inheritance`
Interview-ready guide
Interview answer
JPA offers three inheritance mapping strategies. Each trades normalization, query performance, and null handling differently.
SINGLE_TABLE — one table for all subtypes:
- All fields from all subclasses go in one table; subclass-specific columns are null for other subtypes
- A
DTYPEdiscriminator column identifies the subtype - Fastest: single table, no JOINs for any query
- Problem: nullable columns cannot have NOT NULL constraints; wide tables with sparse data
JOINED — normalized, one table per subclass:
- Parent table holds shared fields; each subclass table holds only subclass-specific fields with FK to parent
- Clean schema, no nulls for subclass-specific columns
- Every polymorphic query requires LEFT JOINs across all subclass tables — expensive for deep hierarchies
TABLE_PER_CLASS — one complete table per concrete class:
- Every concrete class has its own full table; no shared parent table
- Single-type queries are fast; polymorphic queries require UNION ALL across tables
- Not all JPA providers support it equally; avoid for polymorphic queries
`@MappedSuperclass`:
- Not an inheritance strategy — a shared mapping mixin for cross-cutting fields like audit columns
- Cannot query the superclass; no polymorphic associations
Decision rule: few subtypes, mostly shared fields, polymorphic queries -> SINGLE_TABLE; normalized schema with NOT NULL matters -> JOINED; rarely polymorphic -> TABLE_PER_CLASS or skip inheritance.
JPA Inheritance Mapping Strategies
Direct Answer
JPA offers three inheritance strategies plus one mixin. SINGLE_TABLE puts all subclasses in one table with a discriminator column — fastest queries (no JOINs) but every subclass-specific column must be nullable. JOINED stores shared fields in a parent table and subclass fields in separate tables — normalized with NOT NULL constraints, but polymorphic queries require LEFT JOINs across all subtables. TABLE_PER_CLASS gives each concrete class its own complete table — fast single-type queries but polymorphic queries become UNION ALL. @MappedSuperclass is not really inheritance — it shares field mappings without creating a JPA hierarchy, so no polymorphic queries are possible. Default to SINGLE_TABLE for small hierarchies; choose JOINED only when normalized constraints justify the JOIN cost.
Code Example
SINGLE_TABLE:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "vehicle_type", discriminatorType = DiscriminatorType.STRING)
public abstract class Vehicle {
@Id @GeneratedValue Long id;
String vin;
}
@Entity @DiscriminatorValue("CAR")
public class Car extends Vehicle {
Integer numberOfDoors;
}
@Entity @DiscriminatorValue("TRUCK")
public class Truck extends Vehicle {
BigDecimal payloadCapacity;
}
JOINED:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Vehicle {
@Id @GeneratedValue Long id;
@Column(nullable = false) String vin;
}
@Entity
@PrimaryKeyJoinColumn(name = "vehicle_id")
public class Car extends Vehicle {
@Column(nullable = false) Integer numberOfDoors;
}
TABLE_PER_CLASS:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Vehicle {
@Id @GeneratedValue(strategy = GenerationType.TABLE) Long id;
String vin;
}
@MappedSuperclass:
@MappedSuperclass
public abstract class Auditable {
@CreatedDate Instant createdAt;
@LastModifiedDate Instant updatedAt;
}
@Entity
public class Order extends Auditable {
@Id @GeneratedValue Long id;
}
Common Mistakes & Pitfalls
Defaulting to SINGLE_TABLE without realizing every subclass-specific column becomes nullable — violates NOT NULL invariants at the DB level
Check your understanding
Answer these without looking back at the article.
- How do you specify a custom discriminator value for a subclass in SINGLE_TABLE inheritance?
- What SQL does Hibernate generate for a polymorphic `findAll()` with the JOINED strategy?
- Can you mix inheritance strategies across a hierarchy — for example JOINED for some subclasses and SINGLE_TABLE for others?
- When would `@DiscriminatorFormula` be preferable to `@DiscriminatorColumn`?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.