# How to use the OpenAPI discriminator

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?

## oneOf vs. anyOf

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.

![anyOf with title](/assets/1.vehicle-anyof.6aa537b5dbcc499235efc99e01226720c2a281eaa73aeca984011049011713e3.bb292168.png)

Control the button labels by defining a `title` in the corresponding object schema.


```yaml
type: object
title: Gas-powered Vehicle
properties:
  vehicleType:
    description: The type of vehicle.
```

![anyOf with title](/assets/2.vehicle-anyof.379b79715a0882c68b59a888096af8dab4c222e942993173af1a4b2eee402095.bb292168.png)

## When to use the OpenAPI discriminator

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.

Electric Vehicle

```yaml
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: integer
```

Fueled Vehicle

```yaml
type: object
title: Gas-powered Vehicle
properties:
  vehicleType:
    description: The type of vehicle.
    type: string
    example: car
  idealTerrain:
    type: string
    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: Describes how the vehicle is powered.
    type: string
    example: gasoline
  tankCapacity:
    type: number
    format: double
    description: Capacity of the fuel tank in gallons.
  milesPerGallon:
    type: number
    format: double
    description: Miles per gallon on the highway.
```

Pedaled Vehicle

```yaml
type: object
description: Pedaled Vehicle
properties:
  vehicleType:
    description: The type of vehicle.
    type: string
    example: bicycle
    enum:
      - bicycle
  idealTerrain:
    type: string
    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: pedaling
```

The 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.


```yaml
  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.yaml
```

In this example the `powerSource` property must be declared in each of the corresponding schemas.

div
The discriminated property must be of type string.
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](#allof-for-inheritance) 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.

![discriminator gif](/assets/3.vehicle-discriminator.8d088d84925efb221d5d969e96e0ee19b4a9f6103fa83fedd1702d78a2de7ccd.bb292168.gif)

### allOf for inheritance

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`:

Vehicle.yaml

```yaml
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: pedaling
```

PedaledVehicle.yaml

```yaml
# I think of allOf like a "merge"
allOf:
  - $ref: ./Vehicle.yaml
  - type: object
    description: Pedaled Vehicle
    properties:
      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
```

## Common mistakes

### Property outside of the object

The discriminator property name is not inside of the object.
This typically causes the object to not be rendered.

![discriminator property outside of the object](/assets/4.vehicle-common-mistake.62aa4f9e3bdf5f4893ae0e111813c88824bf43008c7bd89bcb1916a255b402bd.bb292168.png)

### Case sensitivity

The discriminator property value is case sensitive (as well as the schema or mapping name).

### Discriminator is described inline

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.



```yaml
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: integer
```

Catch mistakes early by using our [Redocly CLI tool](/redocly-cli).