Inheritance — Joined Strategy
IntermediateBase class gets its own table; subclass tables hold only their columns, joined by PK; good normalisation but requires a JOIN per subclass level on every query.
Overview
In the JOINED strategy, the base class has its own table with shared columns, and each subclass has its own table holding only its additional columns. Both tables share the same primary key — the subclass table's PK is a FK to the base table. Queries always join the base table with the subclass table, adding one JOIN per inheritance level. This strategy is the most normalised: subclass columns can be NOT NULL, no wasted columns, and schema changes are localised. It is the recommended strategy for complex, multi-level hierarchies where data integrity matters more than raw query performance.
Declaring Joined Inheritance
Annotate the base class with @Inheritance(strategy=JOINED). Each subclass table holds only its own columns; Hibernate joins them on the shared PK. A discriminator column is optional but helpful for debugging.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "vehicle_type")
@Table(name = "vehicles")
public abstract class Vehicle {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // table: vehicles(id, make, model, vehicle_type)
private String make;
private String model;
}
@Entity
@DiscriminatorValue("CAR")
@Table(name = "cars")
public class Car extends Vehicle {
private int doors; // table: cars(id FK→vehicles.id, doors)
private String bodyStyle;
}
@Entity
@DiscriminatorValue("TRUCK")
@Table(name = "trucks")
public class Truck extends Vehicle {
private double payloadTons; // table: trucks(id FK→vehicles.id, payload_tons)
}Generated SQL — JOIN on Every Query
A polymorphic query joins all subclass tables. A specific-subclass query joins only the base table + that subclass table. Each level of inheritance adds one more JOIN.
// Polymorphic: SELECT all vehicles
List<Vehicle> all = em.createQuery("SELECT v FROM Vehicle v", Vehicle.class).getResultList();
// Generated SQL (two subclasses):
// SELECT v.id, v.make, v.model, c.doors, c.body_style, t.payload_tons, v.vehicle_type
// FROM vehicles v
// LEFT OUTER JOIN cars c ON v.id = c.id
// LEFT OUTER JOIN trucks t ON v.id = t.id
// Single-type query — inner join only for that subclass
List<Car> cars = em.createQuery("SELECT c FROM Car c", Car.class).getResultList();
// SELECT v.id, v.make, v.model, c.doors, c.body_style
// FROM vehicles v INNER JOIN cars c ON v.id = c.idMulti-Level Joined Inheritance
With multiple levels, each level adds a JOIN. Keep hierarchies shallow (2-3 levels max) to avoid query complexity. Use @PrimaryKeyJoinColumn to customise the FK column name.
@Entity
@Table(name = "electric_cars")
public class ElectricCar extends Car { // 3-level hierarchy
private int rangeKm;
// Query requires 3 tables: vehicles JOIN cars JOIN electric_cars
// SELECT v.*, c.*, e.range_km
// FROM vehicles v
// INNER JOIN cars c ON v.id = c.id
// INNER JOIN electric_cars e ON c.id = e.id
// WHERE v.id = ?
}
// Customise the FK column name in the subclass table
@Entity
@Table(name = "cars")
@PrimaryKeyJoinColumn(name = "vehicle_id") // cars.vehicle_id FK → vehicles.id
public class Car extends Vehicle { ... }Key Points to Remember
- 1JOINED: base class has its own table; each subclass table holds only its additional columns
- 2Subclass tables share PK with base table — the subclass PK is a FK to the base table
- 3Polymorphic queries use LEFT OUTER JOIN across all subclass tables — one JOIN per level
- 4Best normalisation: subclass columns can have NOT NULL; no wasted columns
- 5@PrimaryKeyJoinColumn customises the FK column name in the subclass table
- 6Keep hierarchies shallow — every level adds a JOIN; 2-3 levels is a practical limit
Interview Questions
Sign in to ask AriaHow does the JOINED strategy differ from SINGLE_TABLE for subclass data storage?
What SQL does a polymorphic JOINED query generate?
What is the role of @PrimaryKeyJoinColumn in the JOINED strategy?
Why can JOINED strategy columns have NOT NULL but SINGLE_TABLE cannot?
When would you choose JOINED over SINGLE_TABLE inheritance?
Ask Aria about Inheritance — Joined Strategy
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.