To find a key by value in a TypeScript dictionary, get the keys with Object.keys(), type them as keyof, and call find() to return the first key whose value matches. If nothing matches, you get undefined:
const key = (Object.keys(plans) as (keyof typeof plans)[]).find((k) => plans[k] === 15.49);
Nothing below is pseudo-code: each lookup went through tsc --strict and then Node, using TypeScript 7.0.2 and Node.js v22.22.2, and the printed results are copied from my console.
I’ll also show how to get every matching key, search a Map, build a reverse map, match object values, handle no match, and work with enums.
Find a key by value with Object.keys() and find()
Here’s a dictionary of streaming plan prices, searched with Object.keys(), with Object.entries(), and with a reusable generic helper:
const plans = {
basic: 9.99,
standard: 15.49,
premium: 22.99,
};
// 1. Object.keys() + find(), keys typed as keyof
const key = (Object.keys(plans) as (keyof typeof plans)[]).find(
(k) => plans[k] === 15.49
);
console.log("Object.keys + find: ", key);
// 2. Object.entries() + find(), key and value together
const entry = Object.entries(plans).find(([, price]) => price === 22.99);
console.log("Object.entries + find:", entry?.[0]);
// 3. Reusable generic helper
function findKeyByValue<T extends object>(dict: T, value: T[keyof T]): keyof T | undefined {
return (Object.keys(dict) as (keyof T)[]).find((k) => dict[k] === value);
}
console.log("generic helper: ", findKeyByValue(plans, 9.99));
console.log("no match: ", findKeyByValue(plans, 12.99));
Output:
Object.keys + find: standard
Object.entries + find: premium
generic helper: basic
no match: undefined

The helper returns keyof T | undefined, so the result is "basic" | "standard" | "premium", not just any string. If keyof is new to you, my post on keyof with string keys in TypeScript explains the type.
Object.entries() gives you the pair, but its key is a plain string. Prefer the keyof version when you’ll index the object with it.
Why does TypeScript reject plans[k] inside find()?
Object.keys() is typed as string[] on purpose, because an object can carry extra properties at runtime. Index a typed object with a plain string and strict mode stops you:
const plans = { basic: 9.99, standard: 15.49, premium: 22.99 };
const key = Object.keys(plans).find((k) => plans[k] === 15.49);
Output:
keybyvalue_ts7053.ts(3,44): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ basic: number; standard: number; premium: number; }'.
No index signature with a parameter of type 'string' was found on type '{ basic: number; standard: number; premium: number; }'.

string can’t index an object whose keys are only basic, standard and premium.The cast as (keyof typeof plans)[] fixes it. A Record<string, number> doesn’t need it, since it already accepts any string key, as the next example shows.
Get all keys that share the same value
find() stops at the first match. When several keys can hold the same value, like two Chicago airports, switch to filter() to get every matching key:
const airports: Record<string, string> = {
ORD: "Chicago",
MDW: "Chicago",
LAX: "Los Angeles",
JFK: "New York",
LGA: "New York",
DFW: "Dallas",
};
const first = Object.keys(airports).find((code) => airports[code] === "Chicago");
const all = Object.keys(airports).filter((code) => airports[code] === "Chicago");
console.log("find() ->", first);
console.log("filter() ->", all);
console.log("no match ->", Object.keys(airports).filter((c) => airports[c] === "Boston"));
console.log("any Dallas airport?", Object.values(airports).includes("Dallas"));
Output:
find() -> ORD
filter() -> [ 'ORD', 'MDW' ]
no match -> []
any Dallas airport? true
An empty array means no match, which is easier to handle than undefined. If you only need a yes or no, Object.values().includes() is enough. I cover more callback patterns in filtering arrays in TypeScript.
Find a key by value in a TypeScript Map
A Map has get() for keys but nothing for values. A for...of loop over its entries returns as soon as it finds a match, and spreading into an array lets you use find():
const employees = new Map<number, string>([
[1001, "Emma Johnson"],
[1002, "Liam Smith"],
[1003, "Olivia Brown"],
]);
function findMapKey<K, V>(map: Map<K, V>, value: V): K | undefined {
for (const [key, v] of map) {
if (v === value) return key; // stops at the first match
}
return undefined;
}
console.log("for...of loop: ", findMapKey(employees, "Liam Smith"));
const id = [...employees].find(([, name]) => name === "Olivia Brown")?.[0];
console.log("spread + find: ", id, typeof id);
console.log("not in the Map:", findMapKey(employees, "Noah Davis"));
Output:
for...of loop: 1002
spread + find: 1003 number
not in the Map: undefined
The key comes back as a number: Map keys keep their real type, while object keys are always strings. I compare both in my TypeScript key value pair guide, and here’s how to merge Maps in TypeScript.
Build a reverse map for repeated lookups
Each search by value scans every entry. For frequent lookups, build a value-to-key Map once and call get():
const skuToProduct: Record<string, string> = {
"SKU-1001": "Wireless Mouse",
"SKU-1002": "USB-C Hub",
"SKU-1003": "Laptop Stand",
"SKU-1004": "USB-C Hub",
};
// One key per value: built once, then every lookup is a get()
const productToSku = new Map(
Object.entries(skuToProduct).map(([sku, name]) => [name, sku])
);
console.log("Laptop Stand ->", productToSku.get("Laptop Stand"));
console.log("USB-C Hub ->", productToSku.get("USB-C Hub"), "(last duplicate wins)");
// Every key per value: group with Map.groupBy (ES2024)
const productToSkus = Map.groupBy(Object.entries(skuToProduct), ([, name]) => name);
console.log("USB-C Hub ->", productToSkus.get("USB-C Hub")?.map(([sku]) => sku));
Output:
Laptop Stand -> SKU-1003
USB-C Hub -> SKU-1004 (last duplicate wins)
USB-C Hub -> [ 'SKU-1002', 'SKU-1004' ]

Map.groupBy keeps both.Duplicate values are the catch: the plain reverse map silently overwrites earlier keys, and it won’t update itself, so rebuild it when the dictionary changes. Building lookups from a list is covered in converting an array to a dictionary in TypeScript.
Find a key when the values are objects
Strict equality on objects compares references, not contents. A copy with identical fields won’t match, so compare a property or every field instead:
interface Customer {
name: string;
city: string;
state: string;
}
const customers: Record<string, Customer> = {
C101: { name: "Ava Martinez", city: "Austin", state: "TX" },
C102: { name: "Noah Wilson", city: "Denver", state: "CO" },
C103: { name: "Mia Thompson", city: "Seattle", state: "WA" },
};
const target: Customer = { name: "Noah Wilson", city: "Denver", state: "CO" };
const ids = Object.keys(customers);
console.log("=== on a copy: ", ids.find((id) => customers[id] === target));
console.log("by one property:", ids.find((id) => customers[id].name === target.name));
function sameCustomer(a: Customer, b: Customer): boolean {
return (Object.keys(a) as (keyof Customer)[]).every((k) => a[k] === b[k]);
}
console.log("every field: ", ids.find((id) => sameCustomer(customers[id], target)));
Output:
=== on a copy: undefined
by one property: C102
every field: C102
Match on a unique field, like an email or account number, when you can. sameCustomer only checks top-level fields; nested objects need a recursive deep-equality function.
What if no key matches the value?
Every lookup here can return undefined, and TypeScript makes you deal with it before you use the key:
const plans = { basic: 9.99, standard: 15.49, premium: 22.99 };
const match = (Object.keys(plans) as (keyof typeof plans)[]).find((k) => plans[k] === 12.99);
console.log(plans[match].toFixed(2));
Output:
keybyvalue_undefined_index.ts(4,19): error TS2538: Type 'undefined' cannot be used as an index type.
Narrow the result first with === undefined, or a ?? default. Guards written with the is keyword in TypeScript narrow the same way:
const plans = { basic: 9.99, standard: 15.49, premium: 22.99 };
type Plan = keyof typeof plans;
function findPlan(price: number): Plan | undefined {
return (Object.keys(plans) as Plan[]).find((k) => plans[k] === price);
}
for (const price of [22.99, 12.99]) {
const match = findPlan(price);
if (match === undefined) {
console.log(`No plan costs $${price.toFixed(2)}`);
} else {
console.log(`$${plans[match].toFixed(2)} is the ${match} plan`); // match is Plan here
}
}
console.log("with a default:", findPlan(12.99) ?? "custom");
// The falsy trap: an empty-string key is a real match
const codes: Record<string, string> = { "": "none", A: "active" };
const k = Object.keys(codes).find((c) => codes[c] === "none");
console.log(`found ${JSON.stringify(k)}, but !k says missing:`, !k);
Output:
$22.99 is the premium plan
No plan costs $12.99
with a default: custom
found "", but !k says missing: true
Avoid if (!key), since an empty-string key is a real match that looks missing. When you just want any entry instead of a match, see getting the first element from a TypeScript dictionary.
Find an enum key by value in TypeScript
Numeric enums get a reverse mapping, so OrderStatus[1] returns the member name directly. String enums don’t, so you search their keys like a dictionary. TypeScript enums explained covers the basics:
enum OrderStatus {
Pending,
Shipped,
Delivered,
}
console.log("numeric reverse mapping:", OrderStatus[1]);
console.log("numeric out of range: ", OrderStatus[7]);
console.log("Object.keys(OrderStatus):", Object.keys(OrderStatus));
enum Carrier {
UPS = "ups_ground",
FedEx = "fedex_home",
USPS = "usps_priority",
}
console.log("string enum, no reverse:", (Carrier as Record<string, string>)["fedex_home"]);
const fromApi: string = "fedex_home";
const carrierKey = (Object.keys(Carrier) as (keyof typeof Carrier)[]).find(
(k) => Carrier[k] === fromApi
);
console.log("string enum key: ", carrierKey);
console.log("Object.keys(Carrier): ", Object.keys(Carrier));
Output:
numeric reverse mapping: Shipped
numeric out of range: undefined
Object.keys(OrderStatus): [ '0', '1', '2', 'Pending', 'Shipped', 'Delivered' ]
string enum, no reverse: undefined
string enum key: FedEx
Object.keys(Carrier): [ 'UPS', 'FedEx', 'USPS' ]

Object.keys() plus find().Watch two traps: an out-of-range number gives undefined although it’s typed as string, and Object.keys() on a numeric enum lists the numbers too.
Going the other way? See converting a string to an enum in TypeScript or converting an enum to a number.
Which way to find a key by value should you use?
| Situation | Use | Returns |
|---|---|---|
| Typed object, one match | (Object.keys(o) as (keyof typeof o)[]).find() | keyof or undefined |
| Several keys share a value | Object.keys(o).filter() | Array, empty if none |
Data in a Map | for...of loop or [...map].find() | Original key type or undefined |
| Many lookups by value | Reverse Map built once | get() result |
| Object values | Compare a unique property | Key or undefined |
| String enum | Object.keys(Enum).find() | Member name or undefined |
Ready for more dictionary work? Try one of these next:
- Create a Map from an array in TypeScript
- Loop through an array in TypeScript
- Map an array of objects in TypeScript
- Sort by enum in TypeScript
Frequently asked questions
How do I find a key by value in a TypeScript object?
Use (Object.keys(obj) as (keyof typeof obj)[]).find((k) => obj[k] === value). It returns the first matching key or undefined.
Why do I get error TS7053 with Object.keys()?
Object.keys() returns string[], and a plain string can’t index an object with fixed keys. Cast the array to (keyof typeof obj)[].
How do I get every key with the same value?
Use filter() instead of find(). It returns every matching key, or an empty array.
How do I find a key by value in a Map?
Loop with for (const [k, v] of map) and return on the first match, or use [...map].find(([, v]) => v === value)?.[0].
How do I get an enum key from its value?
Numeric enums support Enum[value]. For string enums, search Object.keys(Enum) with find(), since they have no reverse mapping.
Where is Object.keys() documented?
See Object.keys() on MDN.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn