PostgreSQLTable Inheritance

Table Inheritance

Long before PostgreSQL had declarative partitioning, it already had a distinctly PostgreSQL feature called table inheritance: a child table can inherit the columns of a parent table, and querying the parent automatically includes rows from all of its children. It's modeled loosely on object-oriented inheritance, applied to table structure.

Basic Syntax

table-inheritance.sql

SQL
CREATE TABLE vehicles (
  id SERIAL PRIMARY KEY,
  make TEXT NOT NULL,
  model TEXT NOT NULL
);

-- 'cars' inherits every column from 'vehicles', plus its own extra columns.
CREATE TABLE cars (
  doors INT NOT NULL
) INHERITS (vehicles);

CREATE TABLE motorcycles (
  has_sidecar BOOLEAN NOT NULL DEFAULT false
) INHERITS (vehicles);

INSERT INTO cars (make, model, doors) VALUES ('Toyota', 'Corolla', 4);
INSERT INTO motorcycles (make, model, has_sidecar) VALUES ('Honda', 'CB500', false);

-- Querying the parent returns rows from ALL children by default.
SELECT * FROM vehicles;
-- returns both the Corolla and the CB500 rows

-- ONLY restricts the query to the parent table itself.
SELECT * FROM ONLY vehicles;
Declarative partitioning has largely replaced this for partitioning
Before PostgreSQL 10 introduced declarative partitioning, inheritance was the standard way to build a "partitioned" table: a parent table with `CHECK` constraints on each child and a trigger to route inserts to the right child. That pattern (sometimes still called "legacy" or "inheritance-based" partitioning) is now largely obsolete for new work — declarative partitioning (see the Table Partitioning page) does the same job with far less manual plumbing, built-in partition pruning, and native tooling support. PostgreSQL 9.6, the last version where inheritance-based partitioning was the only option, is very old at this point.

Table inheritance itself is still a real, supported feature — it just isn't the tool of choice for partitioning anymore. It occasionally shows up for genuine "is-a" type hierarchies: modeling a family of related entities that share a common set of columns but each have their own additional attributes, where you still want to query them all together through the parent.

Tip
For new projects: prefer declarative partitioning (`PARTITION BY`) over inheritance whenever the goal is splitting one logical table into pieces. Only reach for plain `INHERITS` if you have a specific, non-partitioning reason to model an actual type hierarchy — and even then, many teams find a single table with a `type` discriminator column simpler to work with in practice.