# Inheritance Mapping Strategies — Hibernate / JPA

Source: https://www.skillbyai.com/en/hibernate-jpa/m-inheritance

> Map class hierarchies with SINGLE_TABLE, JOINED, TABLE_PER_CLASS and @MappedSuperclass.

## Tables for a class hierarchy

Relational databases have no inheritance, so JPA offers strategies. **`@MappedSuperclass`** is not an entity: it just shares mapped fields (such as `id`, `createdAt`, `version`) with subclasses, each of which has its own independent table; you cannot query the superclass polymorphically. **`SINGLE_TABLE`** (the default for `@Inheritance`) stores all subclasses in **one table** with a **discriminator column** (`@DiscriminatorColumn`); it is the fastest for polymorphic queries (no joins), but subclass-specific columns must be nullable, which weakens constraints. **`JOINED`** gives each class its own table, with subclass tables linked by primary key to the parent table; it keeps a normalised schema with proper NOT NULL constraints, at the cost of joins for every polymorphic query. **`TABLE_PER_CLASS`** gives each concrete class a complete table; polymorphic queries need `UNION`s and sequence-based IDs, so it is rarely the best choice. Choose by query patterns: many polymorphic queries favour SINGLE_TABLE; strict constraints and subclass-heavy queries favour JOINED. Often, composition or a simple type field is better than mapping deep hierarchies.

## SINGLE_TABLE and JOINED side by side

Payments in one table with a discriminator; accounts split across joined tables.

```java
@MappedSuperclass
public abstract class BaseEntity {
    @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) protected Long id;
    @Column(nullable = false, updatable = false) protected Instant createdAt = Instant.now();
}

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "method", length = 10)
public abstract class Payment extends BaseEntity {
    protected BigDecimal amount;
}
@Entity @DiscriminatorValue("UPI")  public class UpiPayment  extends Payment { private String vpa; }
@Entity @DiscriminatorValue("CARD") public class CardPayment extends Payment { private String last4; }
// one table: payments(id, created_at, method, amount, vpa NULL, last4 NULL)

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Account extends BaseEntity { protected String owner; }
@Entity public class SavingsAccount extends Account { @Column(nullable = false) private BigDecimal rate; }
@Entity public class LoanAccount    extends Account { @Column(nullable = false) private BigDecimal principal; }
// tables: account(id, created_at, owner), savings_account(id FK, rate), loan_account(id FK, principal)
```

## Polymorphic queries decide the strategy

If you mostly query `select p from Payment p`, SINGLE_TABLE avoids joins. If you mostly query one subtype and need NOT NULL constraints on its columns, JOINED is cleaner. Measure the queries you actually run.

**Quiz:** Which inheritance strategy stores all subclasses in one table with a discriminator column?

- [ ] JOINED
- [ ] TABLE_PER_CLASS
- [x] SINGLE_TABLE
- [ ] @MappedSuperclass

*Answer:* SINGLE_TABLE. SINGLE_TABLE uses one table plus a discriminator to tell rows apart.
