← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

MySQL ENUM Type

database Beginner
debt(d5/e5/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep as the tool, which is a SAST/specialist tool rather than a default linter. It can detect ENUM column patterns on status/state fields, but won't catch all misuse (e.g. silent empty-string corruption in non-strict mode or ORDER BY surprises at runtime).

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix says to replace ENUM with VARCHAR+CHECK or a lookup table. A lookup table refactor touches schema migration, application code referencing the column type, ORM models, and queries — more than a single-line patch but not necessarily a cross-cutting architectural rewrite. This sits at e5.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The choice couples business logic into the database schema — every time a status value must be added, an ALTER TABLE migration is required. This slows multiple work streams (backend changes, migrations, deployments) but is localised to tables that use ENUM rather than shaping the whole system architecture.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field states the canonical trap: developers believe ENUM is 'just a VARCHAR with validation' but it stores integers and ORDER BY sorts by definition index, not alphabetically. Additionally, non-strict mode silently coerces invalid values to empty strings causing data corruption. These behaviours contradict how similar concepts (VARCHAR, CHECK constraints) work elsewhere, placing this squarely at t7.

About DEBT scoring →

Also Known As

MySQL ENUM ENUM column MySQL MySQL SET type

TL;DR

A column that accepts only predefined string values — stored efficiently as integers but with significant schema change pain.

Explanation

ENUM('active', 'inactive', 'pending') stores values as 1-byte integers mapped to the string list. Advantages: compact storage, enforced value set. Disadvantages: adding or removing values requires ALTER TABLE which can lock the table on large datasets; the allowed values are baked into the schema; invalid values silently become empty string in non-strict mode. SET is similar but allows multiple values stored as a bitmask.

Watch Out

ENUM sorts by definition order, not alphabetically. ORDER BY status on an ENUM column returns values in the order they were defined.

Common Misconception

ENUM is just a VARCHAR with validation. ENUM values are stored as integers — ORDER BY ENUM sorts by insertion order in the definition, not alphabetically.

Why It Matters

ENUM looks convenient but couples business logic into the database schema. Adding a status value requires a migration. A lookup table (status_types) is more flexible and avoids locking.

Common Mistakes

  • Using ENUM for status fields that change frequently — adding values requires ALTER TABLE.
  • Relying on ENUM's invalid-value-to-empty-string behaviour in non-strict mode — silent data corruption.
  • Expecting ORDER BY on an ENUM to sort alphabetically — it sorts by index position.

Avoid When

  • Never use ENUM for status fields that change as the business evolves — adding values requires ALTER TABLE.
  • Avoid ENUM with strict mode disabled — invalid values become empty string silently.

When To Use

  • Use ENUM only for truly static values that will never change — e.g. gender (M/F/X) or day_of_week.
  • Prefer MySQL 8 CHECK constraints or a lookup table for values that may grow.

Code Examples

✗ Vulnerable
-- ENUM — adding 'refunded' requires ALTER TABLE (locks large tables)
status ENUM('pending', 'paid', 'shipped', 'cancelled') NOT NULL DEFAULT 'pending'
✓ Fixed
-- Preferred: lookup table for flexible values
CREATE TABLE order_statuses (id TINYINT UNSIGNED PRIMARY KEY, name VARCHAR(50) NOT NULL);
INSERT INTO order_statuses VALUES (1,'pending'),(2,'paid'),(3,'shipped'),(4,'cancelled');

CREATE TABLE orders (
    id        INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    status_id TINYINT UNSIGNED NOT NULL DEFAULT 1,
    FOREIGN KEY (status_id) REFERENCES order_statuses(id)
);

-- Or: MySQL 8 CHECK constraint
status VARCHAR(20) CHECK (status IN ('pending','paid','shipped','cancelled'))

Added 31 Mar 2026
Views 14
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Google 3 Unknown AI 3 Perplexity 1 Meta AI 1 Ahrefs 1
crawler 7 crawler_json 1 pre-tracking 1
DEV INTEL Tools & Severity
⚙ Fix effort: Medium
⚡ Quick Fix
For frequently changing value sets use a VARCHAR with a CHECK constraint or a lookup table — use ENUM only for truly static, rarely changing options
📦 Applies To
web cli
🔗 Prerequisites
🔍 Detection Hints
ENUM column for status/state fields
Auto-detectable: ✓ Yes semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: High Context: File Tests: Regenerate

✓ schema.org compliant