Enums in Business Central

In this webinar — the 20th in the Areopa Academy series — Dmitry Katson covers enums in Business Central from the ground up. Moderated by Luc van Vugt, the session walks through the theory behind enums, their key differences from the older options type, and a series of live AL coding demos. The webinar also addresses the Business Central 16 shift in which Microsoft replaced most built-in options with enums.

Areopa Webinar title slide: Enums in Business Central, presented by Dmitry Katson and moderated by Luc van Vugt, July 7 2020
▶ Watch this segment

Enums vs. Options: What Is the Difference?

For anyone coming from NAV or earlier Business Central versions, options have long been the standard way to present a predefined list of choices. Dmitry opens with a comparison table to highlight where enums go further.

  • Maximum values: Options are limited to 250 characters (roughly 125 values) in a comma-separated string. Enums, as separate objects, support an unlimited number of values.
  • Declaration: An option is a variable-level property with a comma-separated list. An enum is a standalone AL object with its own ID and name.
  • Value key: Each enum value has an explicit integer ID that you assign. Option values are identified by their index position in the list, starting at 0. Enum indexes start at 1 (following Business Central list conventions).
  • Extensibility: Enums marked with Extensible = true can be extended by other apps or extensions. Options cannot be extended at all.
  • Reuse: An enum object can be referenced as a field type in multiple tables and pages. Options must be redeclared wherever they are used.
  • Interface integration: Enums work with AL interfaces, enabling pattern-based design. Options do not support this.
  • Database storage: Both enums and options store as integers at the SQL level — the caption or name is resolved at runtime.
  • Cross-type assignment: Assigning an enum to an option (or vice versa) produces a compiler warning in AL. Assigning between two different enum types also produces a warning or error depending on the enum’s AssignmentCompatibility configuration. Microsoft has indicated these warnings may become errors in a future release.
📖 Docs: Extensible Enums – Microsoft Learn — covers enum declaration syntax, the Extensible property, and enum extension objects with full AL examples.

Defining an Enum in AL

Dmitry demonstrates creating an enum object from scratch inside VS Code. Each value in the enum has a numeric ID and a name. An optional Caption property can be set separately from the name — when omitted, the caption defaults to the name.

enum 50100 "Ocean Fish"
{
    Extensible = true;

    value(1; Tuna)
    {
        Caption = 'Atlantic Bluefin Tuna';
    }
    value(2; Grouper) { }
    value(10; "Blue Marlin") { }
}

The enum is then used as the field type in a table and displayed on a page — no different from any other AL field definition. When a user opens the page, the dropdown shows the enum captions.

field(2; Fish; Enum "Ocean Fish") { }
📖 Docs: Enum Data Type – Microsoft Learn — reference for all built-in enum methods including AsInteger(), Names(), Ordinals(), and FromInteger().

Working with Enum Values in Code

Dmitry covers three common operations developers need when working with enums at runtime.

Getting the ID

Use the AsInteger() method on an enum variable or field to retrieve the numeric ID of the current value:

EnumId := Fish.AsInteger();

Getting the Caption

Use Format() — the same approach as with options:

EnumCaption := Format(Fish);

Getting the Name

The name (not the caption) requires a more involved pattern. Names() returns a List of [Text] indexed by position, not by ID. To get the name for a specific value, first find the index from the ordinals list, then retrieve the name at that index:

var
    EnumName: Text;
    Idx: Integer;
begin
    Idx := "Ocean Fish".Ordinals().IndexOf(Fish.AsInteger());
    EnumName := "Ocean Fish".Names().Get(Idx);
end;

Dmitry shows a common mistake: passing the enum ID directly into Names().Get() causes an out-of-range error when IDs are non-sequential (such as the value with ID 10 in the example above).

Getting an Enum Value from a Text Name

This pattern is useful when reading enum values from JSON in web service scenarios. The FromInteger() method is only available on the enum type itself (not on a variable), so the lookup requires working through the type name:

var
    FishValue: Enum "Ocean Fish";
    Idx: Integer;
    EnumId: Integer;
begin
    Idx := "Ocean Fish".Names().IndexOf(InputText);
    EnumId := "Ocean Fish".Ordinals().Get(Idx);
    FishValue := "Ocean Fish".FromInteger(EnumId);
end;

Changing an Enum ID

Dmitry demonstrates that changing the ID of an existing enum value is possible without a breaking schema change — the integer stored in the database remains whatever was saved. If the ID in the enum definition no longer matches what is in the database, Business Central cannot resolve the caption and shows a blank value. Changing the ID back restores the data display. This is technically possible but generally not recommended.

Reusing Enums Across Objects

Because an enum is a standalone object, it can be passed as a return type from a procedure or used as a parameter. Dmitry shows a confirmation dialog page that returns an Enum "Ocean Fish" value to the calling page, demonstrating how a single enum definition can drive UI choices in multiple places.

Converting Between Different Enum Types

Direct assignment between two different enum types — even if they share the same IDs and value count — is not allowed and produces a compiler error. Dmitry shows two workarounds using integer as an intermediate step:

// Sending side: convert enum to integer
SendingInteger := LakeFish.AsInteger();

// Receiving side: convert integer back to the target enum
OceanFishValue := "Ocean Fish".FromInteger(SendingInteger);

Both conversions produce warnings. The warnings indicate that values may not map correctly if the two enums have different IDs for logically equivalent entries. Dmitry notes this approach works but carries the risk of mismatched values.

Extending Enums

To make an enum extendable, set the Extensible property to true on the base enum. Other extensions can then add values using an enumextension object:

enumextension 50200 "General Journal Account Type Ext" extends "Gen. Journal Account Type"
{
    value(50000; "Custom Type") { }
}

Dmitry also discusses extending the standard Sales Line Type enum, noting that simply adding an enum extension value does not automatically surface the new entry in the Sales Order line type dropdown. Microsoft uses a lookup table approach there to control visibility based on license type, which requires additional codeunit logic to expose custom entries.

📖 Docs: AssignmentCompatibility Property – Microsoft Learn — explains how to configure backwards-compatible assignment between enums that were converted from options, and when this property should or should not be used.

The Business Central 16 Shift

In BC16, Microsoft converted most of the standard options in the base application to enums. However, as Dmitry and Luc discuss, the underlying AL code in the base app was not fully updated at the same time — many assignments between the newly created enums and remaining option-typed fields still generate compiler warnings. Dmitry’s expectation at the time of the webinar was that these warnings could become errors around BC18, following Microsoft’s one-year breaking-change policy. Developers working with BC16 and later should review their custom code for any option-to-enum or enum-to-option assignments and resolve the warnings proactively.

Code Examples on GitHub

All AL code shown during the webinar is available in Dmitry Katson’s GitHub repository, organized into branches covering the different scenarios demonstrated: github.com/dkatson/BC-Enums-Webinar-07-07-20


This post was drafted with AI assistance based on the webinar transcript and video content.