Question

How to Get Enum Entry Names in TypeScript

Question

In TypeScript, how can I iterate over an enum and get the name of each enum member?

For example:

enum MyEnum {
  Entry1,
  Entry2
}

for (const entry in MyEnum) {
  // How can I use the enum member name here,
  // such as "Entry1" or "Entry2"?
}

I want to loop through the enum object and access each declared symbol name.

Short Answer

By the end of this page, you will understand how TypeScript enums are represented at runtime, why iterating over them can produce unexpected results, and how to safely get enum member names. You will also learn the difference between numeric and string enums, common iteration patterns, and when to use alternatives like Object.keys() or Object.values().

Concept

TypeScript enums are a way to define a fixed set of named constants.

For example:

enum MyEnum {
  Entry1,
  Entry2
}

This creates named members:

  • MyEnum.Entry1
  • MyEnum.Entry2

But an important detail is that enums also exist as JavaScript objects at runtime. That means you can loop over them with normal object tools like:

  • for...in
  • Object.keys()
  • Object.values()
  • Object.entries()

Why iteration can be confusing

Numeric enums in TypeScript create reverse mappings.

This enum:

enum MyEnum {
  Entry1,
  Entry2
}

is roughly compiled into something like:

{
  0: "Entry1",
  1: "Entry2",
  Entry1: 0,
  Entry2: 1
}

So if you iterate over it directly, you do not only get the member names. You also get the numeric keys.

That is why beginners often see both of these during iteration:

  • "0"
  • "1"
  • "Entry1"
  • "Entry2"

Why this matters

In real programs, you may want to:

  • build dropdown options from an enum
  • validate input against allowed values
  • display human-readable labels
  • generate configuration lists

If you do not understand enum runtime behavior, your loops may include unwanted keys or values.

Mental Model

Think of a numeric enum like a bilingual dictionary.

It lets you look up in both directions:

  • name -> number
  • number -> name

So for:

enum MyEnum {
  Entry1,
  Entry2
}

TypeScript stores both:

  • Entry1 -> 0
  • 0 -> Entry1
  • Entry2 -> 1
  • 1 -> Entry2

When you loop through the enum object, you are opening the whole dictionary, not just the list of original names.

If you only want the declared member names, you need to filter out the numeric side.

Take Quiz

Syntax and Examples

Basic enum

enum MyEnum {
  Entry1,
  Entry2
}

Using for...in

for (const key in MyEnum) {
  console.log(key);
}

For a numeric enum, this prints:

0
1
Entry1
Entry2

That happens because numeric enums include reverse mapping.

Get only the enum member names

A common approach is to filter out numeric keys:

enum MyEnum {
  Entry1,
  Entry2
}

for (const key in MyEnum) {
  if (isNaN(Number(key))) {
    console.log(key);
  }
}

Output:

Entry1
Entry2

Why this works

  • "0" becomes number 0, so it is numeric
  • "1" becomes number 1, so it is numeric
  • "Entry1" becomes NaN, so it is not numeric
  • "Entry2" becomes NaN, so it is not numeric

Using Object.keys()

enum MyEnum {
  Entry1,
  Entry2
}

const names = Object.keys(MyEnum).filter(key => isNaN(Number(key)));
console.log(names);

Output:

["Entry1", "Entry2"]

This is often cleaner than a for...in loop.

String enums are simpler

enum Status {
  Pending = "PENDING",
  Done = "DONE"
}

console.log(Object.keys(Status));

Output:

["Pending", "Done"]

String enums do not create reverse mappings, so iteration is usually more predictable.

Reusable helper

function getEnumKeys<T extends object>(enumObj: T): string[] {
  return Object.keys(enumObj).filter(key => isNaN(Number(key)));
}

enum MyEnum {
  Entry1,
  Entry2
}

console.log(getEnumKeys(MyEnum));

Output:

["Entry1", "Entry2"]

Step by Step Execution

Consider this code:

enum MyEnum {
  Entry1,
  Entry2
}

const keys = Object.keys(MyEnum);
const names = keys.filter(key => isNaN(Number(key)));

console.log(keys);
console.log(names);

Step 1: Define the enum

enum MyEnum {
  Entry1,
  Entry2
}

At runtime, this behaves roughly like:

{
  0: "Entry1",
  1: "Entry2",
  Entry1: 0,
  Entry2: 1
}

Step 2: Read all object keys

const keys = Object.keys(MyEnum);

keys becomes something like:

["0", "1", "Entry1", "Entry2"]

Step 3: Filter out numeric keys

const names = keys.filter(key => isNaN(Number(key)));

Each item is checked:

  • "0" -> Number("0") is 0 -> numeric -> remove it
  • "1" -> Number("1") is 1 -> numeric -> remove it
  • "Entry1" -> Number("Entry1") is NaN -> keep it
  • "Entry2" -> Number("Entry2") is NaN -> keep it

Step 4: Final result

console.log(names);

Output:

["Entry1", "Entry2"]

This gives you the enum member names only.

Real World Use Cases

Building dropdown menus

You may have an enum for status values:

enum Status {
  Draft,
  Published,
  Archived
}

You can extract names to generate select options.

Validating incoming values

If an API or form sends a value that must match an enum, you can compare against enum keys or values.

Rendering labels in admin panels

Enums are often used for roles, states, categories, or modes. Iterating the enum lets you render all available choices.

Configuration and feature flags

A project may define a small set of supported environments or modes using an enum, then loop through them when building config tools.

Logging and debugging

When debugging state transitions, enum names are easier to read than raw numbers.

Take Quiz

Real Codebase Usage

In real codebases, developers often avoid raw for...in loops on enums unless they specifically understand the enum shape.

Common patterns include:

Using Object.keys() with filtering

const enumNames = Object.keys(MyEnum).filter(key => isNaN(Number(key)));

This is common for numeric enums.

Using string enums for cleaner runtime behavior

enum Role {
  Admin = "ADMIN",
  User = "USER"
}

String enums avoid reverse mapping, which makes iteration easier.

Creating helper utilities

Projects often define one helper and reuse it:

function enumKeys(enumObj: object): string[] {
  return Object.keys(enumObj).filter(key => isNaN(Number(key)));
}

Validation patterns

const allowedStatuses = Object.values(Status);

This is useful when checking user input or API payloads.

Mapping to UI data

const options = Object.keys(Status).map(key => ({
  label: key,
  value: Status[key as keyof typeof Status]
}));

This pattern is common in forms and component libraries.

Guarding against enum surprises

Teams often document whether an enum is numeric or string-based so iteration behaves as expected.

Common Mistakes

Mistake 1: Assuming for...in gives only enum names

Broken expectation:

enum MyEnum {
  Entry1,
  Entry2
}

for (const key in MyEnum) {
  console.log(key);
}

Many beginners expect:

Entry1
Entry2

But they actually get numeric keys too.

Fix

for (const key in MyEnum) {
  if (isNaN(Number(key))) {
    console.log(key);
  }
}

Mistake 2: Forgetting the difference between numeric and string enums

Numeric enum:

enum A {
  One,
  Two
}

String enum:

enum B {
  One = "ONE",
  Two = "TWO"
}

String enums do not have reverse mapping, so iteration is simpler.

Mistake 3: Using enum names when you actually need enum values

enum Status {
  Pending,
  Done
}

const names = Object.keys(Status).filter(key => isNaN(Number(key)));
console.log(names);

This gives:

["Pending", "Done"]

But the values are:

[0, 1]

Know whether you need:

  • member names
  • member values
  • both

Mistake 4: Treating enums like arrays

Broken idea:

console.log(MyEnum.length);

Enums are objects, not arrays. Use Object.keys() or Object.values() instead.

Mistake 5: Not being explicit in UI code

If you build UI options from a numeric enum without filtering, you may show duplicate or invalid entries.

Better

const options = Object.keys(MyEnum)
  .filter(key => isNaN(Number(key)))
  .map(key => ({ label: key, value: MyEnum[key as keyof typeof MyEnum] }));

Comparisons

ApproachWorks with numeric enumsWorks with string enumsReturnsNotes
for...inYesYesKeysNumeric enums include reverse-mapping keys
Object.keys()YesYesKeysUsually the clearest choice
Object.values()YesYesValuesNumeric enums may include both names and numbers
Object.entries()YesYesKey-value pairsUseful when building label/value lists

Numeric enum vs string enum

Enum typeExampleReverse mappingEasier to iterate?
Numeric enumenum A { One, Two }YesNo
String enumenum B { One = "ONE", Two = "TWO" }NoYes

for...in vs Object.keys()

OptionBest useWhy
for...inManual loopingFine, but you usually need filtering
Object.keys()Getting enum names as an arrayCleaner and easier to combine with filter() and map()

In practice, Object.keys() is often the easiest way to get enum member names.

Take Quiz

Cheat Sheet

Get enum names from a numeric enum

enum MyEnum {
  Entry1,
  Entry2
}

const names = Object.keys(MyEnum).filter(key => isNaN(Number(key)));

Get enum names with for...in

for (const key in MyEnum) {
  if (isNaN(Number(key))) {
    console.log(key);
  }
}

Numeric enums

enum A {
  One,
  Two
}

Runtime shape includes both:

  • A.One === 0
  • A[0] === "One"

String enums

enum B {
  One = "ONE",
  Two = "TWO"
}
  • no reverse mapping
  • easier to iterate

Quick rules

  • Enums are runtime objects.
  • Numeric enums create reverse mappings.
  • Object.keys() is usually the clearest way to get names.
  • Filter numeric keys when using numeric enums.
  • Use string enums if you want simpler iteration behavior.

Useful helper

function getEnumNames(enumObj: object): string[] {
  return Object.keys(enumObj).filter(key => isNaN(Number(key)));
}

FAQ

Why does iterating a TypeScript enum return numbers and names?

Because numeric enums create reverse mappings at runtime. The enum object stores both name -> value and value -> name.

How do I get only enum member names in TypeScript?

Use:

Object.keys(MyEnum).filter(key => isNaN(Number(key)))

Do string enums have reverse mapping?

No. String enums do not create reverse mappings, so their keys are simpler to iterate.

Should I use for...in or Object.keys() for enums?

Object.keys() is usually clearer because it returns an array you can easily filter and map.

Can I use Object.values() on enums?

Yes, but with numeric enums it can include both names and numeric values, so be careful.

Are TypeScript enums arrays?

No. Enums are objects at runtime.

What is the easiest enum type to iterate?

String enums are usually easier because they do not include reverse mapping.

Take Quiz

Mini Project

Description

Create a small TypeScript utility that turns an enum into a list of options for a dropdown menu. This demonstrates how to safely extract enum member names and pair them with values, which is a common task in forms and admin dashboards.

Goal

Build a function that converts a TypeScript enum into an array of { label, value } objects using only the real enum member names.

Requirements

  • Define one numeric enum and one string enum.
  • Write a reusable function to extract only enum member names.
  • Create a second function that converts an enum into dropdown-style option objects.
  • Print the results for both enums.
  • Make sure numeric enum reverse-mapping keys are excluded.
Take Quiz

Keep learning

Related questions

View more