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 valuegets the TypeScript type of a valuekeyof SomeTypegets 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
typeofis you looking at that object and writing down its shapekeyofis then reading that written shape and listing its labels
For example, imagine a toolbox:
const tools = {
hammer: 1,
screwdriver: 2,
};
typeof toolssays: “This thing has drawers namedhammerandscrewdriver.”keyof typeof toolssays: “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.
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:
typeof ColorsEnumgets the type of the enum objectkeyofextracts its keys- 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:
whiteblack
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:
- get the type of the value
ColorsEnum - get the keys of that type
- 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.
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 valuereturns a string like"object" - In TypeScript type positions,
typeof valuereturns 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:
keyofworks 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];
Kgives the keys:"white" | "black"Vgives the value types of those keys
These are different ideas.
Comparisons
Related operators and patterns
| Pattern | What it gives you | Example result |
|---|---|---|
typeof value | The type of a value | { white: string; black: string } |
keyof Type | The keys of a type | `"white" |
keyof typeof value | The keys of a value's type | `"white" |
(typeof value)[keyof typeof value] | The value types of a value | string or specific value types |
keyof typeof vs manual union
| Approach | Example | Pros | Cons |
|---|---|---|---|
| Manual union | `type Colors = 'white' | 'black'` | Simple |
keyof typeof | type Colors = keyof typeof ColorsEnum | Always stays in sync | Requires understanding type operators |
Enums vs objects
| Source | Example | keyof typeof ... result |
|---|---|---|
| Enum | enum E { a = 'A', b = 'B' } | `"a" |
| Object | const 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.
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
keyofworks on typestypeofin a type position gets the type of a value- This is different from JavaScript runtime
typeof keyof typeof objgives the keys ofobjkeyof typeof Enumgives 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.
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
- Define a constant object containing at least three status labels.
- Create a type from the object's keys using
keyof typeof. - Write a function that accepts only valid status keys.
- Return the corresponding label from the object.
- Show at least one valid call and one invalid call in comments.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.