Swift
Enum
Dictionary
Equatable
Programming

How can I use a Swift enum as a Dictionary key? Conforming to Equatable

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

To use a Swift enum as a dictionary key, the enum must be Hashable, not just Equatable. Dictionary uses hashing internally to find buckets efficiently, and equality alone is not enough.

That is the key point many short answers miss. Equatable is part of the story because Hashable inherits from it, but the actual requirement for dictionary keys is Hashable.

Why Hashable Matters

A dictionary lookup does two things:

  1. compute a hash for the key
  2. compare keys for equality when hashes collide

That means a key type must support both hashing and equality. In Swift, Hashable gives you both.

This works:

swift
1enum SettingKey: Hashable {
2    case username
3    case email
4    case notificationsEnabled
5}
6
7var settings: [SettingKey: String] = [:]
8settings[.username] = "mark"
9settings[.email] = "[email protected]"
10
11print(settings[.username] ?? "missing")

For an enum with no associated values, this is all you need in modern Swift.

Enums Without Associated Values

Simple enums are the easiest case. When the cases have no associated values, Swift can synthesize Hashable conformance automatically once you declare it.

swift
1enum Screen: Hashable {
2    case home
3    case profile
4    case settings
5}
6
7let titles: [Screen: String] = [
8    .home: "Home",
9    .profile: "Profile",
10    .settings: "Settings"
11]
12
13print(titles[.profile] ?? "Unknown")

You do not need to write == or hash(into:) manually here. Synthesis is the cleanest approach.

Enums With Raw Values

Raw-value enums also work well as dictionary keys:

swift
1enum HTTPHeader: String, Hashable {
2    case contentType = "Content-Type"
3    case authorization = "Authorization"
4    case accept = "Accept"
5}
6
7let headers: [HTTPHeader: String] = [
8    .contentType: "application/json",
9    .accept: "application/json"
10]
11
12print(headers[.contentType] ?? "missing")

The raw value can help with serialization or debugging, but the dictionary still uses the enum value itself as the key.

Enums With Associated Values

Enums with associated values can also be dictionary keys as long as the associated values are themselves Hashable.

swift
1enum CacheKey: Hashable {
2    case user(id: Int)
3    case article(slug: String)
4}
5
6var cache: [CacheKey: String] = [:]
7cache[.user(id: 42)] = "User payload"
8cache[.article(slug: "swift-hashable")] = "Article payload"
9
10print(cache[.user(id: 42)] ?? "missing")

Swift can synthesize the conformance here too because Int and String are Hashable.

Manual Conformance

Manual Hashable implementation is only needed when synthesis cannot express the behavior you want. For example:

swift
1enum CustomKey: Hashable {
2    case file(path: String, version: Int)
3
4    static func == (lhs: CustomKey, rhs: CustomKey) -> Bool {
5        switch (lhs, rhs) {
6        case let (.file(path1, version1), .file(path2, version2)):
7            return path1 == path2 && version1 == version2
8        }
9    }
10
11    func hash(into hasher: inout Hasher) {
12        switch self {
13        case let .file(path, version):
14            hasher.combine(path)
15            hasher.combine(version)
16        }
17    }
18}

Most code should not need this, but it is useful to understand how the requirement works.

When Equatable Alone Is Relevant

You may still see discussions about Equatable because:

  • 'Hashable inherits from Equatable'
  • equality semantics must match hashing semantics
  • old examples often mention both protocols separately

But if the concrete goal is "I want to use this enum as a dictionary key," the correct answer is still: make it Hashable.

Common Pitfalls

The biggest pitfall is trying to conform only to Equatable and expecting Dictionary to accept the enum as a key. It will not. The missing requirement is Hashable.

Another mistake is manually implementing == without keeping it consistent with hash(into:). If two keys compare equal, they must produce matching hash behavior. Breaking that rule causes subtle dictionary bugs.

Developers also over-engineer simple enums. If the enum cases and associated values are already Hashable, let Swift synthesize the implementation.

Finally, be careful if associated values contain non-hashable types. In that case, synthesis fails, and the enum cannot be used as a dictionary key unless you redesign the key representation.

Summary

  • A Swift enum must be Hashable to be used as a dictionary key.
  • 'Equatable alone is not enough.'
  • Simple enums and many enums with associated values get synthesized Hashable conformance automatically.
  • Manual hash(into:) and == are only needed in special cases.
  • Hashing and equality must describe the same notion of key identity.
  • For most enums, enum MyKey: Hashable is the full solution.

Course illustration
Course illustration

All Rights Reserved.