Repository: pydantic/pydantic

Issue:
Schema generation with GenericModel and multiple enums is broken since 1.8.0
### Checks

* [X] I added a descriptive title to this issue
* [X] I have searched (google, github) for similar issues and couldn't find anything
* [X] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug

<!-- Sorry to sound so draconian, but every second saved replying to issues is time spend improving pydantic :-) -->

# Bug

Since pydantic 1.8.0 schema generation with `GenericModel` and multiple `Enum` fields using this GenericModel fails with a `KeyError`. I have tried the fix in https://github.com/samuelcolvin/pydantic/pull/2536 but this seems to be another corner case that has to be fixed.

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.8.1
            pydantic compiled: True
                 install path: /Users/philipp/.pyenv/versions/3.7.10/envs/pydantic_schema_error@3.7.10/lib/python3.7/site-packages/pydantic
               python version: 3.7.10 (default, Mar  4 2021, 21:37:12)  [Clang 12.0.0 (clang-1200.0.32.29)]
                     platform: Darwin-20.3.0-x86_64-i386-64bit
     optional deps. installed: ['typing-extensions']
```
<!-- or if you're using pydantic prior to v1.3, manually include: OS, python version and pydantic version -->

<!-- Please read the [docs](https://pydantic-docs.helpmanual.io/) and search through issues to
confirm your bug hasn't already been reported. -->

<!-- Where possible please include a self-contained code snippet describing your bug: -->

```py
from enum import Enum
from typing import TypeVar, Generic, Optional
from pydantic import BaseModel
from pydantic.generics import GenericModel

ConfigValueT = TypeVar("ConfigValueT")


class ConfigOption(GenericModel, Generic[ConfigValueT]):
    value: ConfigValueT
    value_source: str


class EnumA(str, Enum):
    a = "a"
    aa = "aa"


class EnumB(str, Enum):
    b = "b"
    bb = "bb"


class TestModel(BaseModel):
    option_a: ConfigOption[EnumA]
    option_b: ConfigOption[EnumB]  # it also works with only `option_a` but not with multiple


print(TestModel.schema_json())  # This works until 1.7.3 but crashes on 1.8+
```

This results in a `KeyError`:

```
Traceback (most recent call last):
  File "test.py", line 29, in <module>
    print(TestModel.schema_json())  # This works until 1.7.3 but crashes on 1.8+
  File "pydantic/main.py", line 715, in pydantic.main.BaseModel.schema_json
  File "pydantic/main.py", line 704, in pydantic.main.BaseModel.schema
  File "pydantic/schema.py", line 167, in pydantic.schema.model_schema
  File "pydantic/schema.py", line 548, in pydantic.schema.model_process_schema
  File "pydantic/schema.py", line 589, in pydantic.schema.model_type_schema
  File "pydantic/schema.py", line 241, in pydantic.schema.field_schema
  File "pydantic/schema.py", line 495, in pydantic.schema.field_type_schema
  File "pydantic/schema.py", line 839, in pydantic.schema.field_singleton_schema
KeyError: <class '__main__.ConfigOption[str]'>
```

Thank you for your work on this amazing library!


Discussion:

Resolving patch:
diff --git a/pydantic/typing.py b/pydantic/typing.py
--- a/pydantic/typing.py
+++ b/pydantic/typing.py
@@ -1,5 +1,4 @@
 import sys
-from enum import Enum
 from typing import (  # type: ignore
     TYPE_CHECKING,
     AbstractSet,
@@ -250,14 +249,6 @@ def display_as_type(v: Type[Any]) -> str:
     if not isinstance(v, typing_base) and not isinstance(v, GenericAlias) and not isinstance(v, type):
         v = v.__class__
 
-    if isinstance(v, type) and issubclass(v, Enum):
-        if issubclass(v, int):
-            return 'int'
-        elif issubclass(v, str):
-            return 'str'
-        else:
-            return 'enum'
-
     if isinstance(v, GenericAlias):
         # Generic alias are constructs like `list[int]`
         return str(v).replace('typing.', '')


Test patch:
diff --git a/tests/test_generics.py b/tests/test_generics.py
--- a/tests/test_generics.py
+++ b/tests/test_generics.py
@@ -1111,6 +1111,26 @@ class GModel(GenericModel, Generic[FieldType, ValueType]):
     assert m.dict() == {'field': {'foo': 'x'}}
 
 
+@skip_36
+def test_generic_enums():
+    T = TypeVar('T')
+
+    class GModel(GenericModel, Generic[T]):
+        x: T
+
+    class EnumA(str, Enum):
+        a = 'a'
+
+    class EnumB(str, Enum):
+        b = 'b'
+
+    class Model(BaseModel):
+        g_a: GModel[EnumA]
+        g_b: GModel[EnumB]
+
+    assert set(Model.schema()['definitions']) == {'EnumA', 'EnumB', 'GModel_EnumA_', 'GModel_EnumB_'}
+
+
 @skip_36
 def test_generic_with_user_defined_generic_field():
     T = TypeVar('T')
diff --git a/tests/test_utils.py b/tests/test_utils.py
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -6,7 +6,6 @@
 import sys
 from copy import copy, deepcopy
 from distutils.version import StrictVersion
-from enum import Enum
 from typing import Callable, Dict, List, NewType, Tuple, TypeVar, Union
 
 import pytest
@@ -76,33 +75,6 @@ def test_display_as_type_generic_alias():
     assert display_as_type(list[[Union[str, int]]]) == 'list[[Union[str, int]]]'
 
 
-def test_display_as_type_enum():
-    class SubField(Enum):
-        a = 1
-        b = 'b'
-
-    displayed = display_as_type(SubField)
-    assert displayed == 'enum'
-
-
-def test_display_as_type_enum_int():
-    class SubField(int, Enum):
-        a = 1
-        b = 2
-
-    displayed = display_as_type(SubField)
-    assert displayed == 'int'
-
-
-def test_display_as_type_enum_str():
-    class SubField(str, Enum):
-        a = 'a'
-        b = 'b'
-
-    displayed = display_as_type(SubField)
-    assert displayed == 'str'
-
-
 def test_lenient_issubclass():
     class A(str):
         pass