Study guide
4.4: Enums, Enum Extensions & Extensible Types
Microsoft Dynamics 365 Business Central Developer MB-820
Track your progress as you read
Finished sections get a check mark.
1 Chapter 1: Business Central Architecture & Platform Foundation
1.1 Business Central Architecture & Extensions Model 1.2 Customization Lifecycle: Cloud (SaaS) vs. On-Premises 1.3 Base Application, System Application & AppSource
2 Chapter 2: Development Environment & Configuration
2.1: Development Environment Setup: VS Code, AL: Go! Projects & Sandboxes 2.2: AL Configuration Files: app.json & launch.json Parameters 2.3: Multi-Root Workspaces & Project Dependencies
3 Chapter 3: Extension Lifecycle: Debugging, Deployment, Multilanguage & Maintenance
3.1 Debugging & Snapshot Debugging in Visual Studio Code 3.2 Extension Deployment & Schema Synchronization Modes 3.3 Multilanguage Development with XLIFF & Translation Files 3.4 Extension Maintenance, Deprecation & Breaking Changes
4 Chapter 4: Tables, Table Extensions & Data Modeling
4.1: Building Tables, Fields, Keys & Data Types 4.2: Table Extensions & Table Modifications 4.3: FlowFields, FlowFilters & Table Relations 4.4: Enums, Enum Extensions & Extensible Types
5 Chapter 5: Pages, Page Extensions & Role Centers
5.1: Page Types, Anatomy & Control Structure 5.2: Building Card, List & Document Pages 5.3: Page Extensions & Page Customizations 5.4: Role Centers, Headlines & Cue Data Modeling
6 Chapter 6: Reports & Document Generation
6.1 Report Architecture, DataItems & Dataset Design 6.2 Report Layouts: RDLC, Word, Excel & Multilanguage 6.3 Document Reports & Request Page Programming 6.4 Processing-Only Reports & Report Substitutions
7 Chapter 7: XMLports & Data Exchange
7.1 XMLport Architecture, Formats & Properties 7.2 XMLport Node Hierarchy, Triggers & Stream Manipulation
8 Chapter 8: Codeunits, Events, Triggers & Interfaces
8.1 Codeunit Types, Execution & SingleInstance Codeunits 8.2 Events, Publishers, Subscribers & Event Isolation 8.3 Interfaces, Polymorphism & Dynamic Codeunit Invocation 8.4 Installation & Upgrade Codeunits, Data Transfer & Archive
9 Chapter 9: Entitlements, Permissions & Queries
9.1 Permission Sets & Permission Set Extensions 9.2 Inherent Permissions, Inherent Entitlements & Security Scoping 9.3 Query Objects: Joins, Aggregation & Query as Report Data Source
10 Chapter 10: UI Customization, User Assistance & Onboarding
10.1 Profile Objects & Custom Page Views in AL 10.2 User Assistance: ToolTips, Teaching Tips & In-App Tours 10.3 Assisted Setup, Guided Experience & Onboarding Checklists
11 Chapter 11: Business Central Design Patterns & Data Process Model
11.1 Functional Table Types: Master Data, Supplemental & Setup Patterns 11.2 Document Standards: Header, Line, History & Journal Architectures 11.3 Data Process Model & Posting Routine Architecture
12 Chapter 12: AL Language Fundamentals, Data Types & Variables
12.1 AL Syntax, Variable Scope, Primitive & Complex Data Types 12.2 Expressions, Control Flow Statements & Built-in Functions 12.3 Access Modifiers (Public, Internal, Local) & Code Scoping
13 Chapter 13: Data Manipulation, Streams & Error Handling
13.1 Record Operations: Get, FindSet, ModifyAll & Filter Functions 13.2 Streams, File Management & TempBlob 13.3 Error Handling: ErrorInfo, TryFunctions & Collectible Errors
14 Chapter 14: Testing, Test Toolkit & Automation
14.1 Testing Architecture & the Test Toolkit 14.2 Authoring Test Codeunits & UI Handler Functions
15 Chapter 15: Telemetry, Performance Optimization & Analyzers
15.1 Telemetry Configuration & Azure Application Insights 15.2 Custom Telemetry Signals with Session.LogMessage & KQL 15.3 Performance Profiler, SetLoadFields & Query Optimization 15.4 AL Analyzers: CodeCop, AppSourceCop, UICop & PTECop
16 Chapter 16: REST Web Services & JSON in AL
16.1 HttpClient, HttpRequestMessage & REST API Consumption 16.2 JSON Processing: JsonObject, JsonArray, JsonValue & JsonToken
17 Chapter 17: API Pages, OData, Read Scale-Out & OAuth
17.1 API Pages (PageType=API), OData Web Services & REST Endpoints 17.2 Bound and Unbound OData Actions with [ServiceEnabled] 17.3 Read Scale-Out Architecture & DataAccessIntent Configuration 17.4 Microsoft Entra ID App Registrations & OAuth 2.0 Integration
4.4: Enums, Enum Extensions & Extensible Types
Key Takeaways Explain This Topic AI
AL Enums are first-class, strongly typed objects that replace legacy Option fields to enable modular extensibility across independent extensions.
The Extensible property on an enum controls whether third-party apps can introduce new values via enumextension objects.
AssignmentCompatibility enables implicit assignment between enums and legacy option or integer values, easing backward compatibility during refactoring.
Enums can bind directly to AL interfaces using the implements keyword, with DefaultImplementation and UnknownValueImplementation handling fallback execution.
Ordinal collision avoidance mandates strict range management and gap numbering strategies across AppSource and Per-Tenant extensions.
Last updated: August 2026
4.4 Enums, Enum Extensions & Extensible Types
Prior to the introduction of AL Enums, Business Central utilized Option data types to represent fixed lists of values (e.g., Document Type::Invoice , Status::Open ). Legacy Option fields suffered from a major architectural limitation: they were tightly coupled to the table or variable definition and could not be extended by third-party extensions.
Modern Business Central development replaces Options with AL Enums ( enum objects) and Enum Extensions ( enumextension objects). Enums provide extensible, strongly typed discrete values and serve as the architectural foundation for object-oriented polymorphism via AL Interfaces .
1. AL Enum Declaration & Object Structure
An Enum is declared as an independent AL object with a unique object ID and name. Each entry within an enum is declared as a value consisting of an integer Ordinal Number and an alphanumeric identifier.
- Enum Declaration Syntax enum 50120 "Reward Tier"
- {
- Extensible = true;
- AssignmentCompatibility = true;
- Caption = 'Reward Tier';
- value(0; Bronze)
- {
- Caption = 'Bronze Member';
- }
- value(10; Silver)
- {
- Caption = 'Silver Member';
- }
- value(20; Gold)
- {
- Caption = 'Gold Member';
- }
- value(30; Platinum)
- {
- Caption = 'Platinum VIP';
- }
- }
- Enum Object Properties
Extensible (Boolean):
Extensible = true (Default): Permits other extensions to declare enumextension objects that add new values to this enum.
Extensible = false : Locks the enum. No other extension can add new values. Used for core invariant business logic (such as accounting debit/credit indicators or system status codes).
AssignmentCompatibility (Boolean):
When set to true , the AL compiler allows implicit assignment between this Enum and integer or legacy Option types without requiring explicit type casting ( "Reward Tier"::Silver can be assigned from an integer or option value).
Essential when refactoring legacy base application Option fields to Enums while preserving backward compatibility with existing codeunits.
Caption : Defines the user-facing localized display string for the enum object.
UnknownValueImplementation / DefaultImplementation : Configures interface fallback implementations when binding enums to AL interfaces.
Loading diagram... Enum Extension and Interface Implementation Architecture
2. Ordinal Allocation Strategy & Collision Avoidance
Every enum value requires an explicit integer ordinal. In the underlying SQL database, Business Central stores the integer ordinal rather than the text identifier.
Ordinal Allocation Rules & Best Practices
PTE vs AppSource Ranges: In Per-Tenant Extensions (PTE), custom enum values should use ordinals in the customer's allocated range (e.g., 50000..99999 ). In AppSource ISV packages, ordinals must fall strictly within the publisher's registered Microsoft Partner Center range.
Gap Numbering Strategy: Always space out core enum values (e.g., 0 , 10 , 20 , 30 instead of 0 , 1 , 2 , 3 ). This enables future insertion of intermediate logical values without breaking existing stored ordinal mappings.
Collision Mechanics: If two independent extensions attempt to add an enum extension value using the same ordinal number to the same extensible base enum, a deployment collision error occurs during schema synchronization: Error: An item with the same key has already been added. Key: 50000
Stability Rule: Once an enum value with a given ordinal is published to a production environment, that ordinal must never be changed or reassigned. Changing an ordinal causes data corruption across all table records storing that value.
3. Enum Extensions ( enumextension )
An enumextension object extends an existing extensible enum by adding new values without modifying the original enum definition.
- Enum Extension Syntax enumextension 50125 "Advanced Reward Ext" extends "Reward Tier"
- {
- value(50100; Diamond)
- {
- Caption = 'Diamond Elite Member';
- }
- value(50101; BlackCard)
- {
- Caption = 'Black Card VIP';
- }
- }
- Capabilities and Limitations of Enum Extensions
Additive Only: Enum extensions can only add new values . They cannot delete, hide, or rename existing values declared in the base enum or other extensions.
Target Extensibility Check: An enum extension cannot target an enum whose property is set to Extensible = false .
Unique Identifiers: The identifier name (e.g., Diamond ) and ordinal ( 50100 ) must be unique across the base enum and all active extensions in the tenant.
4. Binding Enums to AL Interfaces (Polymorphism Pattern)
One of the most powerful capabilities in AL is binding Enums to AL Interfaces . This design pattern replaces complex CASE statements with clean, extensible object-oriented polymorphism.
- Step 1: Define the AL Interface interface "IPaymentGateway"
- {
- procedure ProcessPayment(SalesHeader: Record "Sales Header"): Boolean;
- procedure RefundPayment(SalesHeader: Record "Sales Header"): Boolean;
- }
Step 2: Declare the Enum with Interface Implementation enum 50130 "Payment Gateway Type" implements "IPaymentGateway"
- {
- Extensible = true;
- DefaultImplementation = "IPaymentGateway" = "Manual Payment Impl";
- UnknownValueImplementation = "IPaymentGateway" = "Unknown Payment Handler";
- value(0; Manual)
- {
- Caption = 'Manual Cash/Check';
- Implementation = "IPaymentGateway" = "Manual Payment Impl";
- }
- value(10; CreditCard)
- {
- Caption = 'Standard Credit Card';
- Implementation = "IPaymentGateway" = "Credit Card Impl";
- }
- }
- Step 3: Implement the Interface in Codeunits codeunit 50131 "Manual Payment Impl" implements "IPaymentGateway"
- {
- procedure ProcessPayment(SalesHeader: Record "Sales Header"): Boolean
- begin
- Message('Processing manual payment for order %1', SalesHeader."No.");
- exit(true);
- end;
- procedure RefundPayment(SalesHeader: Record "Sales Header"): Boolean
- begin
- exit(true);
- end;
- }
- codeunit 50132 "Credit Card Impl" implements "IPaymentGateway"
- {
- procedure ProcessPayment(SalesHeader: Record "Sales Header"): Boolean
- begin
- // Direct payment gateway API integration
- exit(true);
- end;
- procedure RefundPayment(SalesHeader: Record "Sales Header"): Boolean
- begin
- exit(true);
- end;
- }
- codeunit 50133 "Unknown Payment Handler" implements "IPaymentGateway"
- {
- procedure ProcessPayment(SalesHeader: Record "Sales Header"): Boolean
- begin
- Error('Unrecognized payment gateway type configured on transaction.');
- end;
- procedure RefundPayment(SalesHeader: Record "Sales Header"): Boolean
- begin
- Error('Cannot refund unrecognized payment gateway.');
- end;
- }
- Step 4: Polymorphic AL Invocation codeunit 50140 "Sales Post Hook"
- {
- procedure ExecutePayment(SalesHeader: Record "Sales Header")
- var
- PaymentGateway: Interface "IPaymentGateway";
- begin
- // Cast the enum field directly to the interface variable
- PaymentGateway := SalesHeader."Payment Gateway Type";
- // Invoke polymorphic business logic without ANY 'CASE' statements
- PaymentGateway.ProcessPayment(SalesHeader);
- end;
- }
- DefaultImplementation vs UnknownValueImplementation
DefaultImplementation : Invoked when an enum value does not specify an explicit Implementation = ... mapping for that interface.
UnknownValueImplementation : Invoked when an unassigned, corrupted, or uninstalled extension ordinal value is passed into the interface variable at runtime. This prevents hard unhandled runtime crashes and provides graceful error handling.
5. Migrating Legacy Option Fields to Enums
When modernizing legacy C/AL solutions or refactoring custom extensions, converting Option fields to Enum fields must be executed without corrupting existing database data.
Migration Steps & Schema Synchronization
Declare the Enum: Create a new AL enum object where the value ordinals match the zero-based index positions of the original OptionMembers list ( 0 = Open , 1 = Released , 2 = Pending Approval ).
Change Field Data Type: On the table definition, change field(10; Status; Option) to field(10; Status; Enum "Document Status") .
Preserve Ordinals: Because SQL Server stores both Option and Enum values as integer ordinals in the table column, matching the ordinals guarantees zero data loss during schema synchronization.
Deprecation with Obsolete Properties: If deprecating an old enum value, use ObsoleteState = Pending , ObsoleteReason = '...' , and ObsoleteTag = '...' to signal breaking changes to downstream subscribers. value(99; DeprecatedOption)
- {
- Caption = 'Deprecated Option';
- ObsoleteState = Pending;
- ObsoleteReason = 'Replaced by Cloud Provider API v2.';
- ObsoleteTag = '24.0';
- }