Schema Composition

Combining Schemas

OpenAPI provides powerful keywords for composing complex schemas from simpler ones. Master these patterns to model inheritance, polymorphism, and union types.

Key Concepts
  • allOf - Combine all schemas (AND) - inheritance, mixins
  • oneOf - Exactly one schema (XOR) - polymorphism
  • anyOf - One or more schemas (OR) - union types
  • discriminator - Property that identifies the type (oneOf/anyOf only)

Which One Should I Use?

Use CaseKeywordExample
Extend a base type with more fieldsallOfDog extends Animal
Combine multiple independent traitsallOfPet = Named + Owned + Aged
Value is exactly one of several typesoneOfPet = Cat | Dog | Bird
Accept multiple type variationsanyOfAccept Cat or Dog or both traits
Type detection via property valuediscriminatorpetType: "cat" or "dog"

allOf - Inheritance & Composition

AND

Combines multiple schemas into one. The result must satisfy ALL referenced schemas. Use for inheritance (base + extension) or combining traits.

Inheritance Pattern
components:
schemas:
# Base schema
Animal:
type: object
required: [name]
properties:
name:
type: string
age:
type: integer
# Dog extends Animal
Dog:
allOf:
- $ref: '#/components/schemas/Animal'
- type: object
required: [breed]
properties:
breed:
type: string
bark:
type: boolean

Dog has: name, age (from Animal) + breed, bark (its own)

Mixin Pattern
components:
schemas:
# Trait schemas
Timestamped:
type: object
properties:
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
Identifiable:
type: object
properties:
id:
type: string
format: uuid
# Combine traits
User:
allOf:
- $ref: '#/components/schemas/Identifiable'
- $ref: '#/components/schemas/Timestamped'
- type: object
properties:
email:
type: string

User has: id + createdAt, updatedAt + email

oneOf - Polymorphism

XOR

The value must match exactly ONE of the listed schemas. Use for polymorphic types where instances are distinct variations (e.g., different payment methods).

Pet Polymorphism Example
components:
schemas:
Cat:
type: object
required: [name, meow]
properties:
name:
type: string
meow:
type: boolean
Dog:
type: object
required: [name, bark]
properties:
name:
type: string
bark:
type: boolean
# Pet is either a Cat or a Dog, not both
Pet:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'

Validation Behavior

With oneOf, validation fails if the data matches zero schemas OR multiple schemas. This ensures the value is unambiguously one type.

anyOf - Union Types

OR

The value must match AT LEAST ONE of the listed schemas (can match multiple). More flexible than oneOf - use when schemas might overlap.

Union Type Example
components:
schemas:
# Accept string or integer ID
UserId:
anyOf:
- type: string
- type: integer

Accepts: "abc123" or 12345

Overlapping Schemas
components:
schemas:
ShortText:
type: string
maxLength: 100
Email:
type: string
format: email
# Accepts any valid short text or email
ContactValue:
anyOf:
- $ref: '#/components/schemas/ShortText'
- $ref: '#/components/schemas/Email'

Valid email also matches ShortText - anyOf allows this

Discriminator

Type TagoneOf/anyOf only

A property that identifies which schema variant the data belongs to. Improves validation performance and documentation clarity. Note: Discriminator only works with oneOf and anyOf, not allOf.

Discriminator with oneOf
components:
schemas:
Cat:
type: object
required: [petType, name]
properties:
petType:
type: string
enum: [cat]
name:
type: string
huntsMice:
type: boolean
Dog:
type: object
required: [petType, name]
properties:
petType:
type: string
enum: [dog]
name:
type: string
packAnimal:
type: boolean
Pet:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
discriminator:
propertyName: petType
Valid Cat
{
  "petType": "cat",
  "name": "Whiskers",
  "huntsMice": true
}
Valid Dog
{
  "petType": "dog",
  "name": "Rex",
  "packAnimal": true
}

Discriminator Mapping

When discriminator values don't match schema names, use explicit mapping.

Custom Value Mapping
Pet:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/GermanShepherd'
discriminator:
propertyName: petType
# Map values to schema names
mapping:
cat: '#/components/schemas/Cat'
dog: '#/components/schemas/Dog'
german-shepherd: '#/components/schemas/GermanShepherd'

"petType": "german-shepherd" maps to GermanShepherd schema

Nested Composition

Combine composition keywords for complex type hierarchies.

Base Type with Polymorphic Extension
components:
schemas:
# Base with common fields
PaymentBase:
type: object
required: [amount, currency]
properties:
amount:
type: number
currency:
type: string
# Card payment extends base
CardPayment:
allOf:
- $ref: '#/components/schemas/PaymentBase'
- type: object
required: [paymentType, cardLast4]
properties:
paymentType:
type: string
enum: [card]
cardLast4:
type: string
# Bank payment extends base
BankPayment:
allOf:
- $ref: '#/components/schemas/PaymentBase'
- type: object
required: [paymentType, bankName]
properties:
paymentType:
type: string
enum: [bank]
bankName:
type: string
# Polymorphic union of payment types
Payment:
oneOf:
- $ref: '#/components/schemas/CardPayment'
- $ref: '#/components/schemas/BankPayment'
discriminator:
propertyName: paymentType

Common Mistakes

Missing Discriminator Property

When using discriminator, each schema MUST have the discriminator property.

Wrong

Cat:
properties:
name: ...
# Missing petType!

Correct

Cat:
required: [petType]
properties:
petType:
enum: [cat]
oneOf vs anyOf Confusion

Use oneOf when types are mutually exclusive. Use anyOf when overlap is allowed or intentional. If validation fails because data matches multiple oneOf schemas, consider anyOf.

allOf with Conflicting Properties

When combining schemas with allOf, ensure properties don't conflict. The same property name in multiple schemas should have compatible types.

Best Practices

Always Use Discriminator with oneOf

Makes validation faster and documentation clearer. APIs are easier to use.

Keep Base Schemas Simple

Put only shared properties in base schemas. Let variants add specifics.

Document Each Variant

Add descriptions to each schema in the composition so consumers understand the differences.

Test with Examples

Provide example values for each variant. Tigrister's Preview validates them.