Laravel Typed Enums: Casts, Rules &amp; PHP 8.3 Patterns | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Laravel Typed Enums as First-Class Citizens: Casts, Rules, and PHP 8.3 Features        On this page       1. [  Why Enums Deserve More Than a CastsAttributes Afterthought ](#why-enums-deserve-more-than-a-codecastsattributescode-afterthought)
2. [  1. Backed Enums as Eloquent Casts ](#1-backed-enums-as-eloquent-casts)
3. [  2. Enum-Aware Validation Rules ](#2-enum-aware-validation-rules)
4. [  3. Route Model Binding with Enums ](#3-route-model-binding-with-enums)
5. [  4. PHP 8.3 Typed Class Constants ](#4-php-83-typed-class-constants)
6. [  5. Serialising Enums in API Resources ](#5-serialising-enums-in-api-resources)
7. [  Takeaways ](#takeaways)

  ![Laravel Typed Enums as First-Class Citizens: Casts, Rules, and PHP 8.3 Features](https://cdn.msaied.com/483/0b80ca4c39b98b48f8d3475ac949ea0f.png)

  #laravel   #php   #enums   #eloquent   #api  

 Laravel Typed Enums as First-Class Citizens: Casts, Rules, and PHP 8.3 Features 
=================================================================================

     29 Jul 2026      3 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   Why Enums Deserve More Than a CastsAttributes Afterthought  ](#why-enums-deserve-more-than-a-codecastsattributescode-afterthought)
2. [  02   1. Backed Enums as Eloquent Casts  ](#1-backed-enums-as-eloquent-casts)
3. [  03   2. Enum-Aware Validation Rules  ](#2-enum-aware-validation-rules)
4. [  04   3. Route Model Binding with Enums  ](#3-route-model-binding-with-enums)
5. [  05   4. PHP 8.3 Typed Class Constants  ](#4-php-83-typed-class-constants)
6. [  06   5. Serialising Enums in API Resources  ](#5-serialising-enums-in-api-resources)
7. [  07   Takeaways  ](#takeaways)

 Why Enums Deserve More Than a `CastsAttributes` Afterthought
------------------------------------------------------------

Most teams adopt backed enums, slap `->casts` on the model, and call it done. That leaves a lot of safety on the table. Enums can own their own validation logic, drive route resolution, and — with PHP 8.3 typed class constants — become genuinely self-documenting domain primitives.

---

1. Backed Enums as Eloquent Casts
---------------------------------

Laravel resolves any `BackedEnum` class directly in the `$casts` array:

```php
// app/Enums/OrderStatus.php
enum OrderStatus: string
{
    case Pending   = 'pending';
    case Confirmed = 'confirmed';
    case Shipped   = 'shipped';
    case Cancelled = 'cancelled';

    public function label(): string
    {
        return match($this) {
            self::Pending   => 'Awaiting Payment',
            self::Confirmed => 'Order Confirmed',
            self::Shipped   => 'On Its Way',
            self::Cancelled => 'Cancelled',
        };
    }

    public function isTerminal(): bool
    {
        return in_array($this, [self::Shipped, self::Cancelled], true);
    }
}

```

```php
// app/Models/Order.php
protected $casts = [
    'status' => OrderStatus::class,
];

```

Now `$order->status` is always an `OrderStatus` instance — never a raw string. Calling `$order->status->label()` is safe everywhere without defensive checks.

---

2. Enum-Aware Validation Rules
------------------------------

Laravel ships `Rule::enum()`, but you can push logic into the enum itself for reuse across HTTP and CLI contexts:

```php
use Illuminate\Validation\Rules\Enum;

// In a Form Request
public function rules(): array
{
    return [
        'status' => ['required', new Enum(OrderStatus::class)],
    ];
}

```

For transitions, a custom rule keeps the policy inside the enum:

```php
enum OrderStatus: string
{
    // ... cases above ...

    /** @return self[] */
    public function allowedTransitions(): array
    {
        return match($this) {
            self::Pending   => [self::Confirmed, self::Cancelled],
            self::Confirmed => [self::Shipped,   self::Cancelled],
            default         => [],
        };
    }
}

```

```php
// app/Rules/ValidStatusTransition.php
class ValidStatusTransition implements ValidationRule
{
    public function __construct(private readonly OrderStatus $current) {}

    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $next = OrderStatus::tryFrom($value);

        if ($next === null || ! in_array($next, $this->current->allowedTransitions(), true)) {
            $fail("Cannot transition from {$this->current->value} to {$value}.");
        }
    }
}

```

The rule is instantiated with the *current* status, so the transition matrix lives in one place.

---

3. Route Model Binding with Enums
---------------------------------

Bind an enum directly in a route without a custom resolver:

```php
// routes/api.php
Route::get('/orders/status/{status}', [OrderController::class, 'byStatus']);

```

```php
// app/Http/Controllers/OrderController.php
public function byStatus(OrderStatus $status): JsonResponse
{
    $orders = Order::where('status', $status)->paginate();
    return response()->json($orders);
}

```

Laravel automatically calls `OrderStatus::from($routeValue)` and returns a 404 if the value is invalid — zero boilerplate.

---

4. PHP 8.3 Typed Class Constants
--------------------------------

PHP 8.3 allows typed constants on enums, which is perfect for associating metadata without a separate config file:

```php
enum OrderStatus: string
{
    case Pending   = 'pending';
    case Confirmed = 'confirmed';
    case Shipped   = 'shipped';
    case Cancelled = 'cancelled';

    // Typed constant — enforced by the engine
    const array TERMINAL = [self::Shipped, self::Cancelled];
    const string DEFAULT  = self::Pending->value;
}

```

Now `OrderStatus::TERMINAL` is a typed `array` constant — no docblock needed, and static analysis tools understand it without plugins.

---

5. Serialising Enums in API Resources
-------------------------------------

Avoid leaking raw values or accidentally serialising the enum object:

```php
// app/Http/Resources/OrderResource.php
public function toArray(Request $request): array
{
    return [
        'id'     => $this->id,
        'status' => [
            'value'      => $this->status->value,
            'label'      => $this->status->label(),
            'terminal'   => $this->status->isTerminal(),
        ],
    ];
}

```

Frontend consumers get a stable contract with both machine and human-readable representations.

---

Takeaways
---------

- Use `$casts` with the enum class directly — Laravel handles `BackedEnum` natively.
- Push transition logic into the enum itself; validation rules just delegate to it.
- Route model binding resolves backed enums automatically with a 404 on invalid values.
- PHP 8.3 typed constants let enums carry structured metadata without external config.
- Serialise enums explicitly in API resources to keep frontend contracts stable.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-typed-enums-as-first-class-citizens-casts-rules-and-php-83-features&text=Laravel+Typed+Enums+as+First-Class+Citizens%3A+Casts%2C+Rules%2C+and+PHP+8.3+Features) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-typed-enums-as-first-class-citizens-casts-rules-and-php-83-features) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  Does Laravel automatically validate enum values when casting?        No. The cast silently returns null for invalid values when using `tryFrom` internally. You still need `Rule::enum()` or a custom validation rule in your Form Request to reject bad input before it reaches the model. 

      Q02  Can I use a pure (non-backed) enum as an Eloquent cast?        Not directly. Eloquent's built-in enum cast requires a `BackedEnum` because it needs a scalar value to store in the database. For pure enums you must implement a custom `CastsAttributes` class. 

      Q03  Are PHP 8.3 typed constants on enums supported by PHPStan and Psalm?        Yes. Both PHPStan (level 6+) and Psalm understand typed class constants on enums as of their current stable releases, giving you full static analysis coverage without extra stubs. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![MySQL Query Profiling in Laravel: EXPLAIN ANALYZE, Slow Query Log, and Index Hints](https://cdn.msaied.com/481/8bfc417cb94b3e2868428e065fe4b166.png) laravel mysql performance 

### MySQL Query Profiling in Laravel: EXPLAIN ANALYZE, Slow Query Log, and Index Hints

Stop guessing why a query is slow. Learn how to use EXPLAIN ANALYZE, Laravel's slow query log listener, and in...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 28 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/mysql-query-profiling-in-laravel-explain-analyze-slow-query-log-and-index-hints) [ ![Deploy Next.js and Nuxt Apps on Laravel Cloud](https://cdn.msaied.com/482/f7c51bc5c6a5148320771cfa2bfe217e.png) Laravel Cloud Next.js Nuxt 

### Deploy Next.js and Nuxt Apps on Laravel Cloud

Laravel Cloud now supports deploying Next.js and Nuxt frontends alongside your Laravel backend — same reposito...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 28 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/deploy-nextjs-and-nuxt-apps-on-laravel-cloud) [ ![Laravel Custom Eloquent Relations: Building Polymorphic and Composite-Key Relations](https://cdn.msaied.com/480/c7d2c0d0fd1823460fbdb138f77b573f.png) laravel eloquent database 

### Laravel Custom Eloquent Relations: Building Polymorphic and Composite-Key Relations

Eloquent's built-in relations cover 90% of cases, but composite-key joins and non-standard polymorphic pivots...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 28 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/laravel-custom-eloquent-relations-building-polymorphic-and-composite-key-relations) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
