Backed enums, and the column type that finally matches

A status column had held strings for six years, with no constraint anywhere and three spellings of shipped in production.

enum OrderStatus: string
{
    case Pending   = 'pending';
    case Shipped   = 'shipped';
    case Cancelled = 'cancelled';
}

// the backing type is int or string. nothing else.
// every case must have a value, all distinct, all literal —
// no expressions, no constants, no computed values.

The backing type must be int or string and the values must be compile-time literals, which rules out deriving one from a constant. Choosing string over int is almost always right for something that reaches a database: an integer column is smaller and produces rows nobody can read, and the cost of the string is bytes rather than correctness. The values are now a public contract — renaming a case is free and changing its value is a migration.