# Generic types in enum variants

**URL:** <https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250>\
**Category:** language design\
**Created:** [July 21, 2025, 12:12pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250 "2025-07-21T12:12:05Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![SpaceBroetchen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/spacebroetchen/32/13428_2.png) [@SpaceBroetchen](https://internals.rust-lang.org/u/SpaceBroetchen)\
**Post date:** [July 21, 2025, 12:12pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/1 "2025-07-21T12:12:05Z")

</div>

Hey there,

I needed a very large enum lately, while creating it I wondered why are there no generic types in enum variants?

Obviously you can define global types, but this always leads to different, non compatible types.

My concept of such an enum would look like this:

```rust
pub enum MyEnum {
    TupleLikeVariant<T: Clone + Debug>(T),
    StructLikeVariant<S: Clone> {
        content: S
    },
    NonGenericVariant(u32)
}

```

This enum could be initialized just like every other enum aswell:

```rust
pub fn main() {
    let v1: MyEnum = MyEnum::TupleLikeVariant::<String>(String::from("generic string variant"));
    let v2: MyEnum = MyEnum::StructLikeVariant::<usize>{ content: 123usize };
    let v3: MyEnum = MyEnum::TupleLikeVariant(1.5);
}

```

Obiously you should be able to switch by patterns:

```rust
impl Clone for MyEnum {
    fn clone(&self) -> Self { 
        match self {
            MyEnum::TupleLikeVariant<T>(value) => {
                MyEnum::TupleLikeVariant(value.clone())
            }
            MyEnum::StructLikeVariant {content: value} => {
                MyEnum::StructLikeVariant {
                    content: value.clone()
                }
            }
            MyEnum::NonGenericVariant(value) => MyEnum::NonGenericVariant(value.clone())
        }
    }
}

```

and use it in if clauses:

```rust
pub fn print_it(enum_value: MyEnum) {
    if let MyEnum::TupleLikeVariant::<T>(value) = enum_value {
        println!("{:?}", enum_value);
    }
}

```

the only problem I've come up with is defining explizit representation values to the enum value:

```rust
pub enum MyEnum {
    TupleLikeVariant<T: Clone + Debug>(T) = 42;
}

```

which is obviously not possible due to multiple implementation of one variant. But I guess this could be solved.

Is there any other reason why it would not work and why it is not implemented?

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [July 21, 2025, 12:16pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/2 "2025-07-21T12:16:03Z")

</div>

The issue is how would this be represented in memory. `MyEnum` would be one type, with one representation, but its variants may contain any type `T`.

---

<div class="post-metadata">

**Author:** ![SpaceBroetchen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/spacebroetchen/32/13428_2.png) [@SpaceBroetchen](https://internals.rust-lang.org/u/SpaceBroetchen)\
**Post date:** [July 21, 2025, 12:29pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/3 "2025-07-21T12:29:11Z")

</div>

Yeah thats the idea. The inner type is at every point clearly defined by the variant of the enum. Therefore the compiler should be able to select the actual generated implementation. Or am I missing something?

In the end it is just syntactic sugar for multiple same implementations of different types.

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [July 21, 2025, 12:41pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/4 "2025-07-21T12:41:10Z")

</div>

> [@SpaceBroetchen](#):
>
> Yeah thats the idea. The inner type is at every point clearly defined by the variant of the enum. Therefore the compiler should be able to select the actual generated implementation. Or am I missing something?

That's generally only known at runtime, therefore at compile time the compiler must generate code that handles all possible variants, but this is not possible in your proposal.

> [@SpaceBroetchen](#):
>
> In the end it is just syntactic sugar for multiple same implementations of different types.

What you're describing here is more like the following:

```rs
pub enum MyEnum<T: Clone + Debug> {
    TupleLikeVariant(T),
}

```

If you declare the generic on the variant then you want one type and implementation, not many different ones.

---

<div class="post-metadata">

**Author:** ![rne](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rne/32/12362_2.png) [@rne](https://internals.rust-lang.org/u/rne)\
**Post date:** [July 21, 2025, 12:48pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/5 "2025-07-21T12:48:47Z")

</div>

Indeed, this sounds like you want some kind of "`const enum`" at which point you maybe want to consider using the typestate pattern instead, if you can guarantee all types at compile time anyway.

---

<div class="post-metadata">

**Author:** ![SpaceBroetchen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/spacebroetchen/32/13428_2.png) [@SpaceBroetchen](https://internals.rust-lang.org/u/SpaceBroetchen)\
**Post date:** [July 21, 2025, 1:06pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/6 "2025-07-21T13:06:13Z")

</div>

Your type would lead to different types and I agree that it is partitialy only known at compile time, but this is already the case for enums. If you got different types in enum variants, you obviously can't select during compile time.

The compiler would generate the code for the different cases. This example:

```rust
pub enum MyEnum {
    TupleLikeVariant<T: Clone>(T)
}

pub fn main() {
    let v1: MyEnum = MyEnum::TupleLikeVariant(1usize);
    let v2: MyEnum = MyEnum::TupleLikeVariant(1u32);
    let v3: MyEnum = MyEnum::TupleLikeVariant(String::from("Some String"));
    let v4: MyEnum = MyEnum::TupleLikeVariant(15f32);
    let v5: MyEnum = MyEnum::TupleLikeVariant(-1.3f64);
}

impl Clone for MyEnum {
    fn clone(&self) -> Self { 
        match self {
            MyEnum::TupleLikeVariant<T>(value) => { 
                MyEnum::TupleLikeVariant(value.clone())
            }
        }
    }
}

```

would extend to something like that:

```rust
pub enum MyEnum {
    TupleLikeVariant__usize(usize),
    TupleLikeVariant__u32(u32),
    TupleLikeVariant__String(String),
    TupleLikeVariant__f32(f32),
    TupleLikeVariant__f64(f64),
}

pub fn main() {
    let v1: MyEnum = MyEnum::TupleLikeVariant__usize(1usize);
    let v2: MyEnum = MyEnum::TupleLikeVariant__u32(1u32);
    let v3: MyEnum = MyEnum::TupleLikeVariant__String(String::from("Some String"));
    let v4: MyEnum = MyEnum::TupleLikeVariant__f32(15f32);
    let v5: MyEnum = MyEnum::TupleLikeVariant__f64(-1.3f64);
}

impl Clone for MyEnum {
    fn clone(&self) -> Self { 
        match self {
            MyEnum::TupleLikeVariant__usize(value) => { 
                MyEnum::TupleLikeVariant__usize(value.clone())
            },
            MyEnum::TupleLikeVariant__u32(value) => { 
                MyEnum::TupleLikeVariant__u32(value.clone())
            },
            MyEnum::TupleLikeVariant__String(value) => { 
                MyEnum::TupleLikeVariant__String(value.clone())
            },
            MyEnum::TupleLikeVariant__f32(value) => { 
                MyEnum::TupleLikeVariant__f32(value.clone())
            },
            MyEnum::TupleLikeVariant__f64(value) => { 
                MyEnum::TupleLikeVariant__f64(value.clone())
            },
        }
    }
}

```

At every point it is clear which type should be handled.

> [@rne](#):
>
> Indeed, this sounds like you want some kind of "`const enum`" at which point you maybe want to consider using the typestate pattern instead, if you can guarantee all types at compile time anyway.

The typestate pattern would lead to different types, the target is to have just different variants depending on the usage.

---

<div class="post-metadata">

**Author:** ![tczajka](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tczajka/32/8923_2.png) [@tczajka](https://internals.rust-lang.org/u/tczajka)\
**Post date:** [July 21, 2025, 1:08pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/7 "2025-07-21T13:08:16Z")

</div>

> [@SpaceBroetchen](#):
>
> would extend to something like that:
> 
> ```rust
> pub enum MyEnum {
> TupleLikeVariant__usize(usize),
> TupleLikeVariant__u32(u32),
> TupleLikeVariant__String(String),
> TupleLikeVariant__f32(f32),
> TupleLikeVariant__f64(f64),
> }
> 
> ```

The compiler can't do that because crates are compiled separately. It can't know all the users of the enum in other crates.

---

<div class="post-metadata">

**Author:** ![rne](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rne/32/12362_2.png) [@rne](https://internals.rust-lang.org/u/rne)\
**Post date:** [July 21, 2025, 1:11pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/8 "2025-07-21T13:11:45Z")

</div>

The issue is not about monomorphization, but about layout. In your example, there is no one type `MyEnum` as `let v1: MyEnum = ` suggests. Depending on the monomorphized variant, the type will have a different size and layout, which would actually make it a different type.

If you know your specific subset of types used, you can define `enum MyEnum<A, B>` and then implement all required functionality for all your type combinations explicitly, e.g. `impl MyEnum<usize, String>`. But again, at this point, an enum might have been the wrong choice anyway.

If you want a common type with variable content, you will need to use dynamic types (aka trait objects) within your variants.

---

<div class="post-metadata">

**Author:** ![SpaceBroetchen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/spacebroetchen/32/13428_2.png) [@SpaceBroetchen](https://internals.rust-lang.org/u/SpaceBroetchen)\
**Post date:** [July 21, 2025, 1:47pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/9 "2025-07-21T13:47:58Z")

</div>

> [@tczajka](#):
>
> The compiler can't do that because crates are compiled separately. It can't know all the users of the enum in other crates.

I agree on that problem. Therefore I have another question: How are generics currently compiled? Lets say I got crate A with this code:

```rust
pub fn clone_value<T: Clone>(value: &T) -> T {
    value.clone()
}

```

and crate B with the usage:

```rust
pub fn main() {
    let v = some_clone(30usize);
}

```

is the actual implementation:

```rust
pub fn clone_value__usize(value: &usize) -> usize {
    v.clone()
}

```

In the binary of crate B?

> [@rne](#):
>
> The issue is not about monomorphization, but about layout. In your example, there is no one type `MyEnum` as `let v1: MyEnum = ` suggests. Depending on the monomorphized variant, the type will have a different size and layout, which would actually make it a different type.

As far as I know enums are currently represented the following way:  
The alignment is equal to the largest alignment of all interior types and the representation type. Each variant is represented by first the representation, and following all interior values. Each interior value begins with the padding bytes to align the value, followed by the value itself. At the end are padding bytes to match the size of the largest variant.

Even if you would use generics this concept would work, because you know at compile time how large your largest used generic is.

But it would break appart once you want to add another type from a different crate, this might change the overall size of the enum values and all implementations from other crates would need to be modified.

---

<div class="post-metadata">

**Author:** ![SpaceBroetchen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/spacebroetchen/32/13428_2.png) [@SpaceBroetchen](https://internals.rust-lang.org/u/SpaceBroetchen)\
**Post date:** [July 21, 2025, 1:56pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/10 "2025-07-21T13:56:47Z")

</div>

> [@rne](#):
>
> If you want a common type with variable content, you will need to use dynamic types (aka trait objects) within your variants.

Yes this might be an option, but this would be too much overhead for it. I just implement all types manually.

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [July 21, 2025, 2:28pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/11 "2025-07-21T14:28:20Z")

</div>

> [@SpaceBroetchen](#):
>
> How are generics currently compiled?

Yes, that's pretty much how they are compiled. But differently from your enum proposal, knowledge about **all** uses of the function is not needed to compile one concrete version, for example you did not need to know that `clone_value` might have been called with a `&MyVeryBigType` parameter from another crate.

> [@SpaceBroetchen](#):
>
> Yes this might be an option, but this would be too much overhead for it. I just implement all types manually.

Note that if your idea was possible then trait objects would not need to be `!Sized` and could be compiled in pretty much the same way you would expect here, but there's a reason this is not the case.

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [July 21, 2025, 3:02pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/12 "2025-07-21T15:02:40Z")

</div>

I'm confused by the "this can't be implemented" objections, because isn't this...

```rust
enum MyEnum {
    TupleLikeVariant<T: Clone + Debug>(T),
    StructLikeVariant<S: Clone> {
        content: S
    },
    NonGenericVariant(u32)
}

```

... isomorphic with this, which works just fine today?

```rust
enum MyEnum<T: Clone + Debug, S: Clone> {
    TupleLikeVariant(T),
    StructLikeVariant {
        content: S
    },
    NonGenericVariant(u32),
}

```

---

<div class="post-metadata">

**Author:** ![tczajka](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tczajka/32/8923_2.png) [@tczajka](https://internals.rust-lang.org/u/tczajka)\
**Post date:** [July 21, 2025, 3:17pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/13 "2025-07-21T15:17:31Z")

</div>

> [@zackw](#):
>
> isn't this... ... isomorphic with this

No because in the original proposal the type has no type parameters:

```rust
fn f(e: MyEnum)

```

and in your case it has parameters:

```rust
fn f(e: MyEnum<i32, i32>)

```

You modified the proposal to write the type parameters twice, but that doesn't really make sense, if you have the parameters at the type level you don't need them at the variant level:

```rust
enum MyEnum<T: Clone + Debug, S: Clone> {
    TupleLikeVariant(T),
    StructLikeVariant {
        content: S
    },
    NonGenericVariant(u32)
}
```

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [July 21, 2025, 3:33pm UTC](https://internals.rust-lang.org/t/generic-types-in-enum-variants/23250/14 "2025-07-21T15:33:08Z")

</div>

Oh, I see. I thought OP was just proposing a mild generalization of "enum variants should be first-class types", I didn't realize any erasure of type parameters was involved.

(And I only _meant_ to add type-level type parameters to the bottom half of the hypothetical isomorphism. That they got into the top half as well was an editing mistake.)
