Introduction
Getting an enum's name from its numeric value is a common need when working with APIs, databases, or serialized data that use integer codes instead of symbolic names. Python uses EnumClass(value).name, C# uses Enum.GetName() or casting, Java uses a reverse lookup map, and TypeScript/JavaScript uses bracket notation on the enum object. Each language has different ergonomics and edge cases for reverse enum lookups.
Python
1from enum import Enum
2
3class Color(Enum):
4 RED = 1
5 GREEN = 2
6 BLUE = 3
7
8# Get name from value
9print(Color(1).name) # "RED"
10print(Color(2).name) # "GREEN"
11
12# Get member from value
13color = Color(3)
14print(color) # Color.BLUE
15print(color.name) # "BLUE"
16print(color.value) # 3
17
18# Handle unknown values
19try:
20 Color(99)
21except ValueError as e:
22 print(e) # 99 is not a valid Color
23
24# Safe lookup with a default
25def get_color_name(value, default="UNKNOWN"):
26 try:
27 return Color(value).name
28 except ValueError:
29 return default
30
31print(get_color_name(1)) # "RED"
32print(get_color_name(99)) # "UNKNOWN"
EnumClass(value) returns the enum member with that value. Access .name for the string name and .value for the numeric value. Invalid values raise ValueError.
C#
1public enum Status
2{
3 Active = 1,
4 Inactive = 2,
5 Suspended = 3
6}
7
8// Get name from value
9string name = Enum.GetName(typeof(Status), 1);
10Console.WriteLine(name); // "Active"
11
12// Using nameof for compile-time safety
13Console.WriteLine(nameof(Status.Active)); // "Active"
14
15// Cast integer to enum, then get name
16Status status = (Status)2;
17Console.WriteLine(status.ToString()); // "Inactive"
18
19// Check if value is defined
20bool isDefined = Enum.IsDefined(typeof(Status), 99);
21Console.WriteLine(isDefined); // False
22
23// Get all names and values
24foreach (Status s in Enum.GetValues(typeof(Status)))
25{
26 Console.WriteLine($"{s} = {(int)s}");
27}
28// Active = 1
29// Inactive = 2
30// Suspended = 3
31
32// Safe parse from string
33if (Enum.TryParse<Status>("Active", out Status parsed))
34{
35 Console.WriteLine(parsed); // Active
36}
Enum.GetName() returns the string name or null if the value is not defined. Enum.IsDefined() checks if a value exists before converting.
Java
1public enum Priority {
2 LOW(1),
3 MEDIUM(2),
4 HIGH(3),
5 CRITICAL(4);
6
7 private final int value;
8 private static final Map<Integer, Priority> BY_VALUE = new HashMap<>();
9
10 static {
11 for (Priority p : values()) {
12 BY_VALUE.put(p.value, p);
13 }
14 }
15
16 Priority(int value) {
17 this.value = value;
18 }
19
20 public int getValue() {
21 return value;
22 }
23
24 // Reverse lookup by value
25 public static Priority fromValue(int value) {
26 Priority result = BY_VALUE.get(value);
27 if (result == null) {
28 throw new IllegalArgumentException("Unknown priority value: " + value);
29 }
30 return result;
31 }
32}
33
34// Usage
35Priority p = Priority.fromValue(3);
36System.out.println(p.name()); // "HIGH"
37System.out.println(p.getValue()); // 3
Java enums don't have built-in reverse lookup. The standard pattern is a static Map<Integer, EnumType> populated in a static initializer block.
TypeScript / JavaScript
1// TypeScript numeric enum
2enum Direction {
3 Up = 0,
4 Down = 1,
5 Left = 2,
6 Right = 3,
7}
8
9// Reverse mapping (automatic for numeric enums in TS)
10console.log(Direction[0]); // "Up"
11console.log(Direction[1]); // "Down"
12console.log(Direction["Up"]); // 0
13
14// String enums do NOT have reverse mapping
15enum Color {
16 Red = "RED",
17 Green = "GREEN",
18 Blue = "BLUE",
19}
20
21// Manual reverse lookup for string enums
22function getColorName(value: string): string | undefined {
23 return (Object.keys(Color) as Array<keyof typeof Color>)
24 .find(key => Color[key] === value);
25}
26
27console.log(getColorName("RED")); // "Red"
1// Plain JavaScript object enum pattern
2const Status = Object.freeze({
3 ACTIVE: 1,
4 INACTIVE: 2,
5 SUSPENDED: 3,
6});
7
8// Build reverse map
9const StatusName = Object.fromEntries(
10 Object.entries(Status).map(([key, value]) => [value, key])
11);
12
13console.log(StatusName[1]); // "ACTIVE"
14console.log(StatusName[3]); // "SUSPENDED"
TypeScript numeric enums generate reverse mappings automatically (Direction[0] returns "Up"). String enums do not — you must build the reverse map manually.
Go
1type Weekday int
2
3const (
4 Monday Weekday = iota + 1 // 1
5 Tuesday // 2
6 Wednesday // 3
7 Thursday // 4
8 Friday // 5
9)
10
11// String method for name lookup
12func (d Weekday) String() string {
13 names := map[Weekday]string{
14 Monday: "Monday", Tuesday: "Tuesday", Wednesday: "Wednesday",
15 Thursday: "Thursday", Friday: "Friday",
16 }
17 if name, ok := names[d]; ok {
18 return name
19 }
20 return fmt.Sprintf("Weekday(%d)", d)
21}
22
23// Usage
24fmt.Println(Wednesday) // "Wednesday"
25fmt.Println(Weekday(5)) // "Friday"
26fmt.Println(Weekday(99)) // "Weekday(99)"
Common Pitfalls
Undefined values don't always error: In C#, casting an undefined integer to an enum succeeds silently ((Status)99 is valid but .ToString() returns "99"). Always use Enum.IsDefined() to validate.
TypeScript string enums lack reverse mapping: Only numeric enums get automatic reverse lookups. For string enums, you must build a reverse map manually or iterate over keys.
Java enum ordinal() vs custom value: ordinal() returns the declaration order (0-based), not the custom value. Using ordinal() for persistence breaks when enum members are reordered.
Python IntEnum allows comparison with ints: IntEnum members can be compared directly with integers, but adding or removing members changes nothing — Color(1) still works. Regular Enum is safer for preventing accidental integer comparisons.
Performance of linear search: Building a reverse map once (in a static block or module scope) is O(n) upfront but O(1) per lookup. Iterating through all values on every lookup is O(n) each time.
Summary
Python: EnumClass(value).name — raises ValueError for unknown values
C#: Enum.GetName(typeof(T), value) or ((T)value).ToString() — returns null or stringified int for unknowns
Java: static Map<Integer, EnumType> for reverse lookup — no built-in reverse mapping
TypeScript: EnumName[value] for numeric enums — string enums need manual reverse maps
Always validate that a value maps to a defined enum member before using it
Build reverse lookup maps once at initialization for O(1) access