When an API can return two or more different types of objects (aka polymorphism), use oneOf or anyOf to describe those schemas (a JSON Schema concept). You might also want to use the discriminator (an OpenAPI concept). But why? And how?
Use anyOf when the item might be valid against more than one of the schemas. Use oneOf when it can only be valid against one of the schemas.
How could it be valid against more than one of the schemas? This is easier than you may initially think. Two schemas with some overlapping properties and no other required properties indicate the need for anyOf.
The examples below with the vehicles would require anyOf to be valid.
oneOf and anyOf are visually presented in our reference docs by choice of buttons.

Control the button labels by defining a title in the corresponding object schema.
type: object
title: Gas-powered Vehicle
properties:
vehicleType:
description: The type of vehicle.
Whenever you see the discriminator used, engage in this dialog:
The discriminator adds complexity. Is it necessary?
If the clarity gained by describing the objects distinctly is greater than the cost of the complexity added by doing so, then it may be a good idea to use the discriminator.
It is also possible to create nested discriminators (which involves extra complexity and should be used sparingly).
The discriminator explicitly declares which property you can inspect to determine the object type.
type: object
description: Electric Vehicle
properties:
vehicleType:
description: The type of vehicle.
type: string
example: Tesla
idealTerrain:
type: string
description: A road, river, air... Where does this vehicle thrive?
example: roads
topSpeed:
description: The top speed in kilometers per hour rounded to the nearest integer.
type: integer
example: 83
range:
description: The 95th percentile range of a trip in kilometers.
type: integer
example: 100
powerSource:
description: How is the vehicle powered.
type: string
example: electricity
chargeSpeed:
description: In range kilometers per hour.
type: integer
chargeAmps:
description: Amps recommended for charging.
type: integer
chargeVoltage:
description: Voltage recommended for charging.
type: integerThe discriminator must apply to the same level of the schema it is declared in (common mistake when using nested objects).
Also, it must be used in combination with anyOf, oneOf, or allOf.
We represent the discriminator like a pull down menu on the discriminated property.
requestBody:
content:
application/json:
schema:
discriminator:
propertyName: powerSource
mapping:
electricity: ../components/schemas/ElectricVehicle.yaml
gasoline: ../components/schemas/FueledVehicle.yaml
human-energy: ../components/schemas/PedaledVehicle.yaml
anyOf:
- $ref: ../components/schemas/ElectricVehicle.yaml
- $ref: ../components/schemas/FueledVehicle.yaml
- $ref: ../components/schemas/PedaledVehicle.yamlIn this example the powerSource property must be declared in each of the corresponding schemas.
The mapping is optional and we recommend using it explicitly. If it is not explicitly declared, implicit mapping is introspected from the schema names from the list of schemas included in allOf/anyOf/oneOf including children schema names.
Schema names (including case) must match exactly to the discriminated properties values.
A better alternative is to use the mapping property and making the names explicitly declared. The possible values are determined from introspection by the schema names.

Another common technique used with the discriminator is to define a base schema, and then inherit from it using allOf.
For example, we could have created a base Vehicle schema. Then, each of the specific implementations would "extend" the Vehicle schema using allOf:
type: object
description: Vehicle
discriminator:
propertyName: powerSource
mapping:
electricity: ./ElectricVehicle.yaml
gasoline: ./FueledVehicle.yaml
human-energy: ./PedaledVehicle.yaml
properties:
vehicleType:
description: The type of vehicle.
type: string
example: bicycle
idealTerrain:
type: string
example: roads
powerSource:
description: How is the vehicle powered.
type: string
example: pedalingThe discriminator property name is not inside of the object. This typically causes the object to not be rendered.

The discriminator property value is case sensitive (as well as the schema or mapping name).
The discriminator must use anyOf, oneOf or allOf. When you define it inline, for example, as I did on a version of the ElectricVehicle schema below, it ignores that schema (per the spec):
When using the discriminator, inline schemas will not be considered.
type: object
description: Electric Vehicle
discriminator:
propertyName: powerSource
properties:
vehicleType:
description: The type of vehicle.
type: string
example: bicycle
idealTerrain:
type: string
description: A road, river, air... Where does this vehicle thrive?
example: roads
topSpeed:
description: The top speed in kilometers per hour rounded to the nearest integer.
type: integer
example: 83
range:
description: The 95th percentile range of a trip in kilometers.
type: integer
example: 100
powerSource:
description: How is the vehicle powered.
type: string
example: electricity
chargeSpeed:
description: In range kilometers per hour.
type: integer
chargeAmps:
description: Amps recommended for charging.
type: integer
chargeVoltage:
description: Voltage recommended for charging.
type: integerCatch mistakes early by using our Redocly CLI tool.