diff --git a/src/types/pivotTables/PivotFormat.ts b/src/types/pivotTables/PivotFormat.ts
index 182e511..68b6a00 100644
--- a/src/types/pivotTables/PivotFormat.ts
+++ b/src/types/pivotTables/PivotFormat.ts
@@ -1,4 +1,4 @@
-import type { Style } from '../styles/index.ts';
+import type { integer } from '../integer.ts';
 import type { PivotArea } from './PivotArea.ts';
 
 /**
@@ -8,7 +8,7 @@ import type { PivotArea } from './PivotArea.ts';
  * format targets with an action indicating whether formatting is applied or blanked.
  *
  * Formats are the durable representation of user formatting on pivot output: a consumer
- * re-resolves each format's area against the current layout and overlays its {@link style} on
+ * re-resolves each format's area against the current layout and overlays its differential style on
  * every repaint, so the formatting follows the targeted region (an item's data cells, the grand
  * total row, ...) when the pivot reshapes, rather than sticking to cell coordinates.
  *
@@ -24,9 +24,11 @@ export type PivotFormat = {
   /** The pivot table region this format applies to. */
   pivotArea: PivotArea;
   /**
-   * The formatting to overlay on the area's cells. Only the properties present apply; everything
-   * else on a cell is left as-is (the differential-format semantics of OOXML's `dxf`).
-   * Absent for `action: 'blank'`.
+   * Index of the differential style to overlay on the area's cells, into
+   * {@link Workbook.diffStyles}. Only the properties present in that style apply; everything else
+   * on a cell is left as-is. Absent for `action: 'blank'`.
+   *
+   * @see {@link Workbook.diffStyles}
    */
-  style?: Style;
+  diffStyleId?: integer;
 };
diff --git a/src/types/pivotTables/PivotTable.ts b/src/types/pivotTables/PivotTable.ts
index c2805da..9e4fa14 100644
--- a/src/types/pivotTables/PivotTable.ts
+++ b/src/types/pivotTables/PivotTable.ts
@@ -92,9 +92,9 @@ export type PivotTable = {
   /** Presentation style for the pivot table. */
   style?: PivotTableStyle;
   /**
-   * Custom formatting applied to specific regions of the pivot table. Each format carries its
-   * differential style inline (see {@link PivotFormat.style}); there is no separate dxf table
-   * in JSF.
+   * Custom formatting applied to specific regions of the pivot table. Each format references a
+   * shared differential style by index (see {@link PivotFormat.diffStyleId} and
+   * {@link Workbook.diffStyles}).
    */
   formats?: PivotFormat[];
   // conditionalFormats is omitted for now: the conditional formatting model is not finalized.
diff --git a/src/types/pivotTables/PivotTableStyle.ts b/src/types/pivotTables/PivotTableStyle.ts
index 5593618..5c115fd 100644
--- a/src/types/pivotTables/PivotTableStyle.ts
+++ b/src/types/pivotTables/PivotTableStyle.ts
@@ -7,14 +7,17 @@ import type { PivotTableStyleName } from './PivotTableStyleName.ts';
  */
 export type PivotTableStyle = {
   /**
-   * The name of the pivot table style (e.g. `"PivotStyleMedium9"`).
+   * The name of the pivot table style: either one of the built-in style names
+   * (e.g. `"PivotStyleMedium9"`, see {@link PivotTableStyleName}) or the name of a
+   * workbook-defined style (see {@link Workbook.tableStyles}).
    *
    * If the value is null or omitted the table should not be rendered with any special styling (note
-   * that this only applies if the style object itself is present).
+   * that this only applies if the style object itself is present). A name that is neither a
+   * built-in style name nor defined in the workbook should be treated the same way.
    *
    * @default null
    */
-  name?: PivotTableStyleName | null;
+  name?: PivotTableStyleName | string | null;
   /**
    * Whether row header formatting should be applied.
    *
diff --git a/src/types/tables/TableStyle.ts b/src/types/tables/TableStyle.ts
index 60f3b8a..e2d1270 100644
--- a/src/types/tables/TableStyle.ts
+++ b/src/types/tables/TableStyle.ts
@@ -8,13 +8,16 @@ import type { TableStyleName } from './TableStyleName.ts';
  */
 export type TableStyle = {
   /**
-   * The name of the table style to use with this table.
+   * The name of the table style to use with this table: either one of the built-in style names
+   * ({@link TableStyleName}) or the name of a workbook-defined style (see
+   * {@link Workbook.tableStyles}).
    *
    * If the value is null or omitted the table should not be rendered with any special styling (note
-   * that this only applies if the style object itself is present).
+   * that this only applies if the style object itself is present). A name that is neither a
+   * built-in style name nor defined in the workbook should be treated the same way.
    * @default null
    */
-  name?: TableStyleName | null;
+  name?: TableStyleName | string | null;
   /**
    * Whether row stripe formatting should be applied.
    *
diff --git a/src/types/tables/TableStyleDefinition.ts b/src/types/tables/TableStyleDefinition.ts
new file mode 100644
index 0000000..d991f20
--- /dev/null
+++ b/src/types/tables/TableStyleDefinition.ts
@@ -0,0 +1,31 @@
+import type { TableStyleElement } from './TableStyleElement.ts';
+
+/**
+ * A workbook-defined (custom) style for tables and/or pivot tables.
+ *
+ * Definitions live in {@link Workbook.tableStyles} and are referenced by name from
+ * {@link TableStyle.name} and {@link PivotTableStyle.name}, the same way built-in style
+ * names are referenced.
+ *
+ * A definition only describes the regions it lists; regions without an element get no
+ * formatting from the style. Regions overlap (e.g. a header-row cell is also part of the
+ * whole table), in which case the more specific region's formatting wins, property by
+ * property.
+ *
+ * @group Workbooks
+ */
+export type TableStyleDefinition = {
+  /**
+   * The name of the style, as referenced from tables and pivot tables. Must match the
+   * definition's key in {@link Workbook.tableStyles}.
+   */
+  name: string;
+  /**
+   * Whether this style may be applied to pivot tables, regular tables, or both.
+   *
+   * @default "all"
+   */
+  table?: 'table' | 'pivot' | 'all';
+  /** The formatting of each table region that this style defines. */
+  elements?: TableStyleElement[];
+};
diff --git a/src/types/tables/TableStyleElement.ts b/src/types/tables/TableStyleElement.ts
new file mode 100644
index 0000000..503c57f
--- /dev/null
+++ b/src/types/tables/TableStyleElement.ts
@@ -0,0 +1,29 @@
+import type { integer } from '../integer.ts';
+import type { TableStyleElementType } from './TableStyleElementType.ts';
+
+/**
+ * The formatting of one region of a table or pivot table, within a
+ * {@link TableStyleDefinition}.
+ *
+ * @group Workbooks
+ */
+export type TableStyleElement = {
+  /** The table region this element's formatting applies to. */
+  type: TableStyleElementType;
+  /**
+   * The number of consecutive rows or columns in each stripe band. Only meaningful for the
+   * four stripe element types.
+   *
+   * @default 1
+   */
+  size?: integer;
+  /**
+   * Index of the differential style to overlay on the region's cells, into
+   * {@link Workbook.diffStyles}. Only the properties present in that style apply; everything else
+   * on a cell is left as-is. An element without a `diffStyleId` has no visual effect (a stripe
+   * element may still carry a meaningful {@link size}).
+   *
+   * @see {@link Workbook.diffStyles}
+   */
+  diffStyleId?: integer;
+};
diff --git a/src/types/tables/TableStyleElementType.ts b/src/types/tables/TableStyleElementType.ts
new file mode 100644
index 0000000..5269a45
--- /dev/null
+++ b/src/types/tables/TableStyleElementType.ts
@@ -0,0 +1,71 @@
+/**
+ * The region of a table or pivot table that a {@link TableStyleElement} applies to.
+ *
+ * Some regions only occur in tables (e.g. `totalRow`), others only in pivot tables (e.g.
+ * `pageFieldLabels`, the subheading and subtotal regions); a style definition usable for
+ * both kinds of table may include elements for both.
+ *
+ * The `Kind` column below indicates which kind of table each region applies to.
+ *
+ * | Value                    | Kind  | Region
+ * |--------------------------|-------|-----------------------------------------------------------
+ * | `wholeTable`             | both  | The entire table.
+ * | `headerRow`              | both  | The header row.
+ * | `totalRow`               | table | The totals row.
+ * | `firstColumn`            | both  | The first column.
+ * | `lastColumn`             | both  | The last column.
+ * | `firstRowStripe`         | both  | Odd row stripes (the first, third, … band of rows).
+ * | `secondRowStripe`        | both  | Even row stripes (the second, fourth, … band of rows).
+ * | `firstColumnStripe`      | both  | Odd column stripes (the first, third, … band of columns).
+ * | `secondColumnStripe`     | both  | Even column stripes (the second, fourth, … band of columns).
+ * | `firstHeaderCell`        | table | The first cell of the header row.
+ * | `lastHeaderCell`         | table | The last cell of the header row.
+ * | `firstTotalCell`         | table | The first cell of the totals row.
+ * | `lastTotalCell`          | table | The last cell of the totals row.
+ * | `firstSubtotalColumn`    | pivot | First-level subtotal columns.
+ * | `secondSubtotalColumn`   | pivot | Second-level subtotal columns.
+ * | `thirdSubtotalColumn`    | pivot | Third-level subtotal columns.
+ * | `firstSubtotalRow`       | pivot | First-level subtotal rows.
+ * | `secondSubtotalRow`      | pivot | Second-level subtotal rows.
+ * | `thirdSubtotalRow`       | pivot | Third-level subtotal rows.
+ * | `blankRow`               | pivot | Blank rows.
+ * | `firstColumnSubheading`  | pivot | First-level column subheadings.
+ * | `secondColumnSubheading` | pivot | Second-level column subheadings.
+ * | `thirdColumnSubheading`  | pivot | Third-level column subheadings.
+ * | `firstRowSubheading`     | pivot | First-level row subheadings.
+ * | `secondRowSubheading`    | pivot | Second-level row subheadings.
+ * | `thirdRowSubheading`     | pivot | Third-level row subheadings.
+ * | `pageFieldLabels`        | pivot | Page field label cells (the filter-field name cells).
+ * | `pageFieldValues`        | pivot | Page field value cells (the filter-field selection cells).
+ *
+ * @group Workbooks
+ */
+export type TableStyleElementType =
+  'wholeTable' |
+  'headerRow' |
+  'totalRow' |
+  'firstColumn' |
+  'lastColumn' |
+  'firstRowStripe' |
+  'secondRowStripe' |
+  'firstColumnStripe' |
+  'secondColumnStripe' |
+  'firstHeaderCell' |
+  'lastHeaderCell' |
+  'firstTotalCell' |
+  'lastTotalCell' |
+  'firstSubtotalColumn' |
+  'secondSubtotalColumn' |
+  'thirdSubtotalColumn' |
+  'firstSubtotalRow' |
+  'secondSubtotalRow' |
+  'thirdSubtotalRow' |
+  'blankRow' |
+  'firstColumnSubheading' |
+  'secondColumnSubheading' |
+  'thirdColumnSubheading' |
+  'firstRowSubheading' |
+  'secondRowSubheading' |
+  'thirdRowSubheading' |
+  'pageFieldLabels' |
+  'pageFieldValues';
diff --git a/src/types/tables/index.ts b/src/types/tables/index.ts
index f09df54..d32c703 100644
--- a/src/types/tables/index.ts
+++ b/src/types/tables/index.ts
@@ -2,4 +2,7 @@ export type * from './Table.ts';
 export type * from './TableColumn.ts';
 export type * from './TableColumnDataType.ts';
 export type * from './TableStyle.ts';
+export type * from './TableStyleDefinition.ts';
+export type * from './TableStyleElement.ts';
+export type * from './TableStyleElementType.ts';
 export type * from './TableStyleName.ts';
diff --git a/src/types/workbooks/Workbook.ts b/src/types/workbooks/Workbook.ts
index df81daa..7565fc3 100644
--- a/src/types/workbooks/Workbook.ts
+++ b/src/types/workbooks/Workbook.ts
@@ -3,7 +3,7 @@ import type { DefinedName } from '../DefinedName.ts';
 import type { External } from '../External.ts';
 import type { NamedStyle } from '../styles/index.ts';
 import type { Style } from '../styles/index.ts';
-import type { Table } from '../tables/index.ts';
+import type { Table, TableStyleDefinition } from '../tables/index.ts';
 import type { Theme } from '../themes/index.ts';
 import type { PivotTable } from '../pivotTables/index.ts';
 import type { Worksheet } from '../worksheets/index.ts';
@@ -31,8 +31,32 @@ export type Workbook = {
   calculationProperties?: CalcProps;
   /** Styles for cells in the workbook. */
   styles?: Style[];
+  /**
+   * Differential styles: partial style overrides referenced by index from features that overlay
+   * formatting on top of a cell's own style rather than replacing it (pivot table formats, custom
+   * table styles, and future dynamic/conditional styles).
+   *
+   * This is the differential-overlay analog of {@link Workbook.styles}: where {@link Cell.s}
+   * indexes a complete cell style in `styles`, an overlay's `diffStyleId` indexes a partial
+   * override here. Only the properties present in an entry apply; everything else on the target
+   * cell is left as-is.
+   *
+   * Each entry reuses the {@link Style} type (already all-optional), but is interpreted
+   * differentially: an absent property means "leave unchanged", not "use the default".
+   *
+   * @see {@link PivotFormat.diffStyleId}
+   */
+  diffStyles?: Style[];
   /** Named cell style definitions (e.g. "Normal", "Heading 1"), keyed by style name. */
   namedStyles?: Record<string, NamedStyle>;
+  /**
+   * Workbook-defined (custom) table and pivot table style definitions, keyed by style name.
+   *
+   * Tables and pivot tables reference these definitions by name, through
+   * {@link TableStyle.name} and {@link PivotTableStyle.name}, the same way they reference
+   * the built-in style names.
+   */
+  tableStyles?: Record<string, TableStyleDefinition>;
   /** External cells referenced by the workbook. An external cell is a cell in another workbook. */
   externals?: External[];
   /**
