TABLE_PER_CLASS

One Complete Table per Concrete Class

With TABLE_PER_CLASS each concrete subclass gets a full table with all columns, inherited ones included. There is no parent table.

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Payment {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)   // IDENTITY is not allowed: ids must be unique across tables
    private Long id;
    private BigDecimal amount;
}

@Entity @Table(name = "card_payments") public class CardPayment extends Payment { private String cardLast4; }
@Entity @Table(name = "upi_payments")  public class UpiPayment  extends Payment { private String upiId; }
-- select p from Payment p: a UNION ALL of every table
select p1_0.id,p1_0.clazz_,p1_0.amount,p1_0.card_last4,p1_0.upi_id
from (
    select id, amount, card_last4, null as upi_id, 1 as clazz_ from card_payments
    union all
    select id, amount, null as card_last4, upi_id, 2 as clazz_ from upi_payments
) p1_0

When It Fits

  • Pros: queries on one concrete type touch one table with no joins and no NULL columns.
  • Cons: polymorphic queries and associations to Payment need UNION ALL; no IDENTITY ids; changing a parent field alters every table.

Note: If you almost never query the parent type, consider @MappedSuperclass instead: same tables, simpler.