JOINED

A Table per Class, Joined by Primary Key

With JOINED, the parent table holds the shared columns and each subclass has its own table with only its fields. The subclass primary key is also a foreign key to the parent.

@Entity
@Table(name = "payments")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Payment { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private BigDecimal amount; }

@Entity @Table(name = "card_payments") public class CardPayment extends Payment { @Column(nullable = false) private String cardLast4; }
@Entity @Table(name = "upi_payments")  public class UpiPayment  extends Payment { @Column(nullable = false) private String upiId; }
create table payments      (id bigint not null auto_increment, amount decimal(38,2), primary key (id));
create table card_payments (id bigint not null, card_last4 varchar(255) not null, primary key (id));
create table upi_payments  (id bigint not null, upi_id varchar(255) not null, primary key (id));
alter table card_payments add constraint FK... foreign key (id) references payments (id);
alter table upi_payments  add constraint FK... foreign key (id) references payments (id);

Saving and Querying

-- persisting a UpiPayment: two inserts
insert into payments (amount) values (?)
insert into upi_payments (upi_id,id) values (?,?)

-- select p from Payment p: left join every subclass table, CASE picks the class
select p1_0.id,
       case when p1_1.id is not null then 1 when p1_2.id is not null then 2 end,
       p1_0.amount,p1_1.card_last4,p1_2.upi_id
from payments p1_0
left join card_payments p1_1 on p1_0.id=p1_1.id
left join upi_payments p1_2 on p1_0.id=p1_2.id
  • Pros: normalized schema, NOT NULL constraints on subclass columns, no wasted space.
  • Cons: polymorphic queries join all subclass tables; inserts write two rows. Slower with deep or wide hierarchies.