Question

Understanding `keyof typeof` in TypeScript

typescripttypeofunion-typeskeyof

Question

In TypeScript, what does keyof typeof mean, and how does it work in a case like this?

enum ColorsEnum {
  white = '#ffffff',
  black = '#000000',
}

type Colors = keyof typeof ColorsEnum;

In this example, Colors becomes:

type Colors = "white" | "black";

I want to understand why that happens.

I would expect typeof ColorsEnum to return something like "Object", and then keyof "Object" would not seem very useful. Clearly, that is not how TypeScript is interpreting it. What exactly do typeof and keyof mean here, and why do they produce the union of enum member names?

Short Answer

By the end of this page, you will understand that typeof in TypeScript can refer to the type of a value, not JavaScript's runtime string result, and keyof extracts the property names from that type. Together, keyof typeof SomeValue turns an object-like value such as an enum or object literal into a union of its keys, like "white" | "black".

Concept

In TypeScript, typeof and keyof are both type operators, but they do different jobs.

  • typeof value gets the TypeScript type of a value
  • keyof SomeType gets a union of the property names of a type

The important point is that this is not the same as JavaScript runtime behavior.

typeof in JavaScript vs TypeScript

In JavaScript:

typeof ColorsEnum // "object"

That returns a runtime string.

In TypeScript type positions:

type T = typeof ColorsEnum;

This does not produce the string "object". Instead, it produces the type shape of the ColorsEnum value.

For this enum:

enum ColorsEnum {
  white = '#ffffff',
  black = '#000000',
}

TypeScript treats ColorsEnum as a value that looks roughly like this:

{
  white: string;
  black: string;
}

So:

type T = typeof ColorsEnum;

means “get the type of the enum object.”

Then keyof extracts that type's property names:

type Colors = keyof typeof ColorsEnum;

which becomes:

type Colors = "white" | "black";

Why this matters

This pattern is useful because it lets you derive types from actual values.

That means:

  • fewer duplicated definitions
  • safer refactoring
  • better autocomplete
  • fewer typos in string literals

If you rename a key in the original object or enum, the derived type updates automatically.

Mental Model

Think of it like this:

  • A value is a real object sitting on a table
  • typeof is you looking at that object and writing down its shape
  • keyof is then reading that written shape and listing its labels

For example, imagine a toolbox:

const tools = {
  hammer: 1,
  screwdriver: 2,
};
  • typeof tools says: “This thing has drawers named hammer and screwdriver.”
  • keyof typeof tools says: “Give me the drawer names only.”

Result:

"hammer" | "screwdriver"

So with keyof typeof, you are not asking JavaScript what kind of thing something is at runtime. You are asking TypeScript to inspect a value's structure and turn its property names into a type.

Take Quiz

Syntax and Examples

Core syntax

type Keys = keyof typeof someValue;

This works when someValue is a value known to TypeScript, such as:

  • an enum
  • an object literal
  • an imported constant object

Example with an enum

enum ColorsEnum {
  white = '#ffffff',
  black = '#000000',
}

type Colors = keyof typeof ColorsEnum;
// "white" | "black"

Explanation:

  1. typeof ColorsEnum gets the type of the enum object
  2. keyof extracts its keys
  3. The final result is a union of enum member names

Example with an object

const config = {
  host: 'localhost',
  port: 3000,
  secure: true,
};

type ConfigKey = keyof typeof config;
// "host" | "port" | "secure"

This is the same idea as the enum example.

Using the derived type

enum ColorsEnum {
  white = '#ffffff',
  black = '#000000',
}

type Colors = keyof typeof ColorsEnum;

function getColorHex(name: Colors) {
  return ColorsEnum[name];
}

getColorHex('white'); // ok
getColorHex('black'); // ok
// getColorHex('blue'); // error

This is useful because only valid enum keys are allowed.

Step by Step Execution

Consider this example:

enum ColorsEnum {
  white = '#ffffff',
  black = '#000000',
}

type EnumType = typeof ColorsEnum;
type ColorKeys = keyof EnumType;

Now walk through it.

Step 1: Define the enum

enum ColorsEnum {
  white = '#ffffff',
  black = '#000000',
}

At runtime, this creates an object-like value with properties:

  • white
  • black

Step 2: Apply typeof

type EnumType = typeof ColorsEnum;

TypeScript reads the value ColorsEnum and gets its type.

You can think of EnumType as roughly:

type EnumType = {
  white: ColorsEnum.white;
  black: ColorsEnum.black;
};

The exact internal type is more specific, but this mental picture is enough.

Step 3: Apply keyof

type ColorKeys = keyof EnumType;

keyof looks at the properties of EnumType and extracts their names:

type ColorKeys = "white" | "black";

Step 4: Use the result

let colorName: ColorKeys;

colorName = 'white'; // ok
colorName = 'black'; // ok
// colorName = 'blue'; // error

So the whole expression:

keyof typeof ColorsEnum

means:

  1. get the type of the value ColorsEnum
  2. get the keys of that type
  3. return them as a union of string literal types

Real World Use Cases

keyof typeof is common whenever you want to keep values and types in sync.

1. Enum key validation

enum Status {
  pending = 'PENDING',
  done = 'DONE',
}

type StatusKey = keyof typeof Status;

Useful when you want accepted strings to exactly match enum member names.

2. Configuration keys

const settings = {
  theme: 'dark',
  language: 'en',
  notifications: true,
};

type SettingKey = keyof typeof settings;

This helps when writing functions that receive a valid config key.

3. Form field names

const fields = {
  email: '',
  password: '',
  confirmPassword: '',
};

type FieldName = keyof typeof fields;

Useful in form validation and error handling.

4. API mapping objects

const routes = {
  users: '/api/users',
  posts: '/api/posts',
};

type RouteName = keyof typeof routes;

This prevents invalid route names from being used elsewhere.

5. Feature flags

const features = {
  newDashboard: true,
  betaCheckout: false,
};

type FeatureName = keyof typeof features;

This is useful for toggling features safely across a codebase.

Take Quiz

Real Codebase Usage

In real projects, developers often use keyof typeof to avoid repeating string unions manually.

Common pattern: derive types from constants

Instead of this:

type Theme = 'light' | 'dark';

const themes = {
  light: '#fff',
  dark: '#000',
};

developers often write:

const themes = {
  light: '#fff',
  dark: '#000',
};

type Theme = keyof typeof themes;

Now the keys and the type stay synchronized.

Guard clauses with known keys

const messages = {
  success: 'Saved',
  error: 'Failed',
};

type MessageKey = keyof typeof messages;

function getMessage(key: MessageKey) {
  return messages[key];
}

This gives autocomplete and compile-time safety.

Validation helpers

const validators = {
  email: (v: string) => v.includes('@'),
  password: (v: string) => v.length >= 8,
};

type ValidatorName = keyof typeof validators;

function runValidator(name: ValidatorName, value: string) {
  return validators[name](value);
}

Configuration-driven code

const env = {
  development: 'dev.example.com',
  production: 'example.com',
};

type EnvName = keyof typeof env;

This pattern is especially useful in:

  • config modules
  • route maps
  • event names
  • translation keys
  • reducer/action maps
  • permission systems

Common Mistakes

Mistake 1: Confusing TypeScript typeof with JavaScript typeof

Broken expectation:

type T = typeof ColorsEnum;
// expecting "object"

Why it is wrong:

  • In JavaScript expressions, typeof value returns a string like "object"
  • In TypeScript type positions, typeof value returns the value's type

How to avoid it:

  • Ask yourself whether you are in a runtime expression or a type annotation/type alias

Mistake 2: Using keyof directly on a value name

Broken code:

const user = {
  name: 'Ada',
  age: 30,
};

type UserKeys = keyof user;

Why it fails:

  • keyof works on a type, not directly on a value

Correct version:

const user = {
  name: 'Ada',
  age: 30,
};

type UserKeys = keyof typeof user;

Mistake 3: Expecting enum values instead of enum keys

enum ColorsEnum {
  white = '#ffffff',
  black = '#000000',
}

type Colors = keyof typeof ColorsEnum;
// "white" | "black"

Some beginners expect:

"#ffffff" | "#000000"

But keyof returns the property names, not the property values.

Mistake 4: Forgetting that object keys may widen

const obj = {
  a: 1,
  b: 2,
};

type K = keyof typeof obj;

This is fine, but if you are also trying to preserve exact values, you may need as const.

const obj = {
  a: 1,
  b: 2,
} as const;

keyof typeof obj still gives "a" | "b", but as const helps preserve exact value literals too.

Mistake 5: Mixing up keys and indexed access

type K = keyof typeof ColorsEnum;
type V = (typeof ColorsEnum)[K];
  • K gives the keys: "white" | "black"
  • V gives the value types of those keys

These are different ideas.

Comparisons

Related operators and patterns

PatternWhat it gives youExample result
typeof valueThe type of a value{ white: string; black: string }
keyof TypeThe keys of a type`"white"
keyof typeof valueThe keys of a value's type`"white"
(typeof value)[keyof typeof value]The value types of a valuestring or specific value types

keyof typeof vs manual union

ApproachExampleProsCons
Manual union`type Colors = 'white''black'`Simple
keyof typeoftype Colors = keyof typeof ColorsEnumAlways stays in syncRequires understanding type operators

Enums vs objects

SourceExamplekeyof typeof ... result
Enumenum E { a = 'A', b = 'B' }`"a"
Objectconst o = { a: 1, b: 2 }`"a"

Keys vs values

const roles = {
  admin: 'ADMIN',
  user: 'USER',
} as const;

type RoleKey = keyof typeof roles;
// "admin" | "user"

type RoleValue = (typeof roles)[keyof typeof roles];
// "ADMIN" | "USER"

Use keyof typeof when you want names. Use indexed access when you want values.

Take Quiz

Cheat Sheet

Quick reference

Get keys from an enum or object

type Keys = keyof typeof someValue;

Example with enum

enum ColorsEnum {
  white = '#ffffff',
  black = '#000000',
}

type ColorKeys = keyof typeof ColorsEnum;
// "white" | "black"

Example with object

const config = {
  host: 'localhost',
  port: 3000,
};

type ConfigKeys = keyof typeof config;
// "host" | "port"

Get values instead of keys

type Values = (typeof someValue)[keyof typeof someValue];

Important rules

  • keyof works on types
  • typeof in a type position gets the type of a value
  • This is different from JavaScript runtime typeof
  • keyof typeof obj gives the keys of obj
  • keyof typeof Enum gives enum member names

Common use cases

  • enum member name unions
  • config key types
  • route names
  • form field names
  • translation keys

Easy memory trick

  • typeof = “what type is this value?”
  • keyof = “what keys does this type have?”
  • keyof typeof = “what are the keys of this value?”

FAQ

What does keyof typeof mean in TypeScript?

It means: first get the type of a value using typeof, then get that type's property names using keyof.

Why does typeof not return "object" here?

Because in a type context, TypeScript's typeof is a type operator, not JavaScript's runtime operator. It returns the value's type shape, not a runtime string.

Does keyof typeof work only with enums?

No. It also works with object literals, imported constant objects, and other named values that TypeScript can inspect.

Does keyof typeof ColorsEnum give enum keys or enum values?

It gives the enum keys, such as "white" | "black", not the values like "#ffffff" | "#000000".

How do I get the values instead of the keys?

Use indexed access:

type ColorValues = (typeof ColorsEnum)[keyof typeof ColorsEnum];

When should I use keyof typeof?

Use it when you want a type to be derived from a real value so your code stays in sync automatically.

Is keyof typeof better than writing the union by hand?

Usually yes, when the keys already exist in an object or enum. It reduces duplication and makes refactoring safer.

Take Quiz

Mini Project

Description

Build a small TypeScript utility that stores application status labels and lets you safely look them up by name. This demonstrates how keyof typeof can create a type directly from an object so only valid status names are accepted.

Goal

Create a type-safe status lookup function that only accepts keys defined in a status map.

Requirements

  1. Define a constant object containing at least three status labels.
  2. Create a type from the object's keys using keyof typeof.
  3. Write a function that accepts only valid status keys.
  4. Return the corresponding label from the object.
  5. Show at least one valid call and one invalid call in comments.
Take Quiz

Keep learning

Related questions

View more