OrvalOrval

Enum Extensions

Generate enums with names and descriptions using OpenAPI extensions

Use OpenAPI extensions and OpenAPI 3.1 enum metadata to generate enums with meaningful names and descriptions.

OpenAPI Schema

Use x-enumNames to assign meaningful names to enum members, and x-enumDescriptions to add JSDoc comments that appear in IDE tooltips.

openapi: '3.1.0'
info:
  version: 1.0.0
  title: Swagger Petstore
components:
  schemas:
    MyObject:
      type: object
      properties:
        myEnum:
          type: number
          enum:
            - 1
            - 2
            - 3
            - 4
          x-enumNames:
            - One
            - Two
            - Three
            - Four
          x-enumDescriptions:
            - Represents the first value
            - Represents the second value
            - Represents the third value
            - Represents the fourth value

Generated Output

export const MyEnum = {
  /** Represents the first value */
  One: 1,
  /** Represents the second value */
  Two: 2,
  /** Represents the third value */
  Three: 3,
  /** Represents the fourth value */
  Four: 4,
} as const;

export type MyEnum = typeof MyEnum[keyof typeof MyEnum];

Supported Extensions

Orval recognizes the following extensions:

Enum names:

  • x-enumNames
  • x-enumnames
  • x-enum-varnames

Enum descriptions:

  • x-enumDescriptions
  • x-enumdescriptions
  • x-enum-descriptions

OpenAPI 3.1 const enums

enumGenerationType: 'enum' emits a TypeScript enum declaration. enum syntax cannot be erased by type stripping, so generated 'enum' output does not compile under TypeScript 5.8+ erasableSyntaxOnly (e.g. Node's native TypeScript support). In that environment use const (default) or union — see the enumGenerationType reference.

OpenAPI 3.1 enum-like schemas using oneOf with const branches can use title, description, and deprecated as member metadata.

components:
  schemas:
    Status:
      oneOf:
        - const: PENDING
          title: Pending
          description: Awaiting manual review
        - const: LEGACY
          title: Legacy
          description: No longer issued
          deprecated: true

With const enum generation, Orval preserves the branch metadata:

export const Status = {
  /** Awaiting manual review */
  Pending: 'PENDING',
  /**
   * No longer issued
   * @deprecated
   */
  Legacy: 'LEGACY',
} as const;

export type Status = typeof Status[keyof typeof Status];

When a branch has no title, its member name is derived from the const value and respects output.override.namingConvention.enum.

Unannotated oneOf/const branches retain their existing union output.

Zod

Metadata generates z.enum({ ... }) for Zod 4 and z.nativeEnum({ ... } as const) for Zod 3, while boolean or mixed-type enums remain literal unions and enums without metadata retain their existing output

When metadata produces an enum object (z.enum({ Cat: 'cat', ... })), the generator always emits constant-style key: value pairs and deliberately ignores the enumGenerationType setting. The object is inserted as an object-literal argument, where union ('cat' | 'dog') and enum (Cat = 'cat') output are not valid — either would make the generated code fail to parse. If you need union or enum-style output, apply it to enums without metadata instead.

oneOf/const branches

Annotated oneOf/const branches keep the union-of-literals shape. Each annotated branch carries its title, description and deprecated in .meta(), so the values stay readable at runtime through zod.globalRegistry:

export const Status = zod.union([
  zod
    .literal('PENDING')
    .meta({ title: 'Pending', description: 'Awaiting manual review' }),
  zod.literal('LEGACY').meta({
    title: 'Legacy',
    description: 'No longer issued',
    deprecated: true,
  }),
]);

Status.options.map((o) => ({ value: o.value, ...zod.globalRegistry.get(o) }));

This does not need output.override.zod.generateMeta. Per Zod version:

Zod versionOutput
Zod 4.meta({ title, description, deprecated }) on each annotated branch
Zod 4 Mini.check(zod.meta({ ... })) on each annotated branch
Zod 3No registry, so branches keep .describe(description) and title/deprecated are dropped

Branches that carry only a description keep .describe(). Branches with no metadata stay a bare zod.literal(...), so a spec without member metadata produces the same output as before.

On this page