diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
 Unreleased
 ----------
 
+3.2.4
+-----
+- Give `title` to sub schemas of sum types [#88](https://github.com/biocad/openapi3/pull/88).
+
 3.2.3
 -----
 
diff --git a/openapi3.cabal b/openapi3.cabal
--- a/openapi3.cabal
+++ b/openapi3.cabal
@@ -1,6 +1,6 @@
 cabal-version:       >=1.10
 name:                openapi3
-version:             3.2.3
+version:             3.2.4
 
 synopsis:            OpenAPI 3.0 data model
 category:            Web, Swagger, OpenApi
@@ -28,11 +28,15 @@
    || ==8.8.4
    || ==8.10.7
    || ==9.0.2
-   || ==9.2.2
+   || ==9.2.7
+   || ==9.4.5
+   || ==9.6.1
 
 custom-setup
   setup-depends:
-    base, Cabal, cabal-doctest >=1.0.6 && <1.1
+    base < 5,
+    Cabal < 4,
+    cabal-doctest >=1.0.6 && <1.1
 
 library
   hs-source-dirs:      src
@@ -61,10 +65,10 @@
 
   -- GHC boot libraries
   build-depends:
-      base             >=4.11.1.0  && <4.18
+      base             >=4.11.1.0  && <4.19
     , bytestring       >=0.10.8.2  && <0.12
     , containers       >=0.5.11.0  && <0.7
-    , template-haskell >=2.13.0.0  && <2.20
+    , template-haskell >=2.13.0.0  && <2.21
     , time             >=1.8.0.2   && <1.14
     , transformers     >=0.5.5.0   && <0.7
 
@@ -74,8 +78,8 @@
 
   -- other dependencies
   build-depends:
-      base-compat-batteries     >=0.11.1   && <0.13
-    , aeson                     >=1.4.2.0  && <1.6 || >=2.0.1.0 && < 2.2
+      base-compat-batteries     >=0.11.1   && <0.14
+    , aeson                     >=1.4.2.0  && <1.6 || >=2.0.1.0 && < 2.3
     , aeson-pretty              >=0.8.7    && <0.9
     -- cookie 0.4.3 is needed by GHC 7.8 due to time>=1.4 constraint
     , cookie                    >=0.4.3    && <0.5
@@ -99,8 +103,8 @@
   hs-source-dirs:   test
   main-is:          Spec.hs
 
-  -- From library parat
- -- We need aeson's toEncoding for doctests too
+  -- From library part
+  -- We need aeson's toEncoding for doctests too
   build-depends:
       base
     , QuickCheck
@@ -121,14 +125,14 @@
 
   -- test-suite only dependencies
   build-depends:
-      hspec                >=2.5.5   && <2.11
+      hspec                >=2.5.5   && <2.12
     , HUnit                >=1.6.0.0 && <1.7
     , quickcheck-instances >=0.3.19  && <0.14
     , utf8-string          >=1.0.1.1 && <1.1
 
   -- https://github.com/haskell/cabal/issues/3708
   build-tool-depends:
-    hspec-discover:hspec-discover >=2.5.5 && <2.11
+    hspec-discover:hspec-discover >=2.5.5 && <2.12
 
   other-modules:
     SpecCommon
diff --git a/src/Data/OpenApi.hs b/src/Data/OpenApi.hs
--- a/src/Data/OpenApi.hs
+++ b/src/Data/OpenApi.hs
@@ -392,6 +392,7 @@
 --                 "userId",
 --                 "tag"
 --             ],
+--             "title": "ErrorNoUser",
 --             "type": "object"
 --         },
 --         {
@@ -410,6 +411,7 @@
 --                 "requiredPermission",
 --                 "tag"
 --             ],
+--             "title": "ErrorAccessDenied",
 --             "type": "object"
 --         }
 --     ]
diff --git a/src/Data/OpenApi/Internal/Schema.hs b/src/Data/OpenApi/Internal/Schema.hs
--- a/src/Data/OpenApi/Internal/Schema.hs
+++ b/src/Data/OpenApi/Internal/Schema.hs
@@ -27,6 +27,7 @@
 import Control.Lens hiding (allOf)
 import Data.Data.Lens (template)
 
+import Control.Applicative ((<|>))
 import Control.Monad
 import Control.Monad.Writer hiding (First, Last)
 import Data.Aeson (Object (..), SumEncoding (..), ToJSON (..), ToJSONKey (..),
@@ -1026,7 +1027,7 @@
          ) => GToSchema (f :+: g)
    where
   -- Aeson does not unwrap unary record in sum types.
-  gdeclareNamedSchema opts p s = gdeclareNamedSumSchema (opts { unwrapUnaryRecords = False } )p s
+  gdeclareNamedSchema opts = gdeclareNamedSumSchema (opts { unwrapUnaryRecords = False })
 
 gdeclareNamedSumSchema :: GSumToSchema f => SchemaOptions -> Proxy f -> Schema -> Declare (Definitions Schema) NamedSchema
 gdeclareNamedSumSchema opts proxy _
@@ -1055,8 +1056,15 @@
 -- | Convert one component of the sum to schema, to be later combined with @oneOf@.
 gsumConToSchemaWith :: forall c f. (GToSchema (C1 c f), Constructor c) =>
   Maybe (Referenced Schema) -> SchemaOptions -> Proxy (C1 c f) -> (T.Text, Referenced Schema)
-gsumConToSchemaWith ref opts _ = (tag, schema)
+gsumConToSchemaWith ref opts _ = (tag, withTitle)
   where
+    -- Give sub-schemas @title@ attribute with constructor name, if none present.
+    -- This will look prettier in swagger-ui.
+    withTitle = case schema of
+      Inline sub -> Inline $ sub
+        & title %~ (<|> Just (T.pack constructorName))
+      s -> s
+
     schema = case sumEncoding opts of
       TaggedObject tagField contentsField ->
         case ref of
@@ -1064,13 +1072,13 @@
           -- to the record, as Aeson does it.
           Just (Inline sub) | sub ^. type_ == Just OpenApiObject && isRecord -> Inline $ sub
             & required <>~ [T.pack tagField]
-            & properties . at (T.pack tagField) ?~ (Inline $ mempty & type_ ?~ OpenApiString & enum_ ?~ [String tag])
+            & properties . at (T.pack tagField) ?~ Inline (mempty & type_ ?~ OpenApiString & enum_ ?~ [String tag])
 
           -- If it is not a record, we need to put subschema into "contents" field.
           _ | not isRecord -> Inline $ mempty
             & type_ ?~ OpenApiObject
             & required .~ [T.pack tagField]
-            & properties . at (T.pack tagField) ?~ (Inline $ mempty & type_ ?~ OpenApiString & enum_ ?~ [String tag])
+            & properties . at (T.pack tagField) ?~ Inline (mempty & type_ ?~ OpenApiString & enum_ ?~ [String tag])
               -- If constructor is nullary, there is no content.
             & case ref of
                 Just r -> (properties . at (T.pack contentsField) ?~ r) . (required <>~ [T.pack contentsField])
@@ -1081,7 +1089,7 @@
             & allOf ?~ [Inline $ mempty
               & type_ ?~ OpenApiObject
               & required .~ (T.pack tagField : if isRecord then [] else [T.pack contentsField])
-              & properties . at (T.pack tagField) ?~ (Inline $ mempty & type_ ?~ OpenApiString & enum_ ?~ [String tag])]
+              & properties . at (T.pack tagField) ?~ Inline (mempty & type_ ?~ OpenApiString & enum_ ?~ [String tag])]
             & if isRecord
                  then allOf . _Just <>~ [refOrNullary]
                  else allOf . _Just <>~ [Inline $ mempty & type_ ?~ OpenApiObject & properties . at (T.pack contentsField) ?~ refOrNullary]
@@ -1092,7 +1100,8 @@
         & properties . at tag ?~ refOrNullary
       TwoElemArray -> error "unrepresentable in OpenAPI 3"
 
-    tag = T.pack (constructorTagModifier opts (conName (Proxy3 :: Proxy3 c f p)))
+    constructorName = conName (Proxy3 :: Proxy3 c f p)
+    tag = T.pack (constructorTagModifier opts constructorName)
     isRecord = conIsRecord (Proxy3 :: Proxy3 c f p)
     refOrNullary = fromMaybe (Inline nullarySchema) ref
     refOrEnum = fromMaybe (Inline $ mempty & type_ ?~ OpenApiString & enum_ ?~ [String tag]) ref
diff --git a/test/Data/OpenApi/CommonTestTypes.hs b/test/Data/OpenApi/CommonTestTypes.hs
--- a/test/Data/OpenApi/CommonTestTypes.hs
+++ b/test/Data/OpenApi/CommonTestTypes.hs
@@ -277,6 +277,7 @@
         "tag",
         "contents"
       ],
+      "title": "PC",
       "type": "object",
       "properties": {
         "tag": {
@@ -296,6 +297,7 @@
         "npcPosition",
         "tag"
       ],
+      "title": "NPC",
       "type": "object",
       "properties": {
         "tag": {
@@ -326,6 +328,7 @@
         "tag",
         "contents"
       ],
+      "title": "PC",
       "type": "object",
       "properties": {
         "tag": {
@@ -367,6 +370,7 @@
         "npcPosition",
         "tag"
       ],
+      "title": "NPC",
       "type": "object",
       "properties": {
         "tag": {
@@ -410,6 +414,7 @@
         "tag",
         "contents"
       ],
+      "title": "PC",
       "type": "object",
       "properties": {
         "tag": {
@@ -437,6 +442,7 @@
         "npcPosition",
         "tag"
       ],
+      "title": "NPC",
       "type": "object",
       "properties": {
         "tag": {
@@ -636,6 +642,7 @@
       "required": [
         "tag"
       ],
+      "title": "NoLight",
       "type": "object",
       "properties": {
         "tag": {
@@ -651,6 +658,7 @@
         "tag",
         "contents"
       ],
+      "title": "LightFreq",
       "type": "object",
       "properties": {
         "tag": {
@@ -670,6 +678,7 @@
         "tag",
         "contents"
       ],
+      "title": "LightColor",
       "type": "object",
       "properties": {
         "tag": {
@@ -688,6 +697,7 @@
         "waveLength",
         "tag"
       ],
+      "title": "LightWaveLength",
       "type": "object",
       "properties": {
         "tag": {
@@ -714,6 +724,7 @@
       "required": [
         "tag"
       ],
+      "title": "NoLight",
       "type": "object",
       "properties": {
         "tag": {
@@ -729,6 +740,7 @@
         "tag",
         "contents"
       ],
+      "title": "LightFreq",
       "type": "object",
       "properties": {
         "tag": {
@@ -748,6 +760,7 @@
         "tag",
         "contents"
       ],
+      "title": "LightColor",
       "type": "object",
       "properties": {
         "tag": {
@@ -771,6 +784,7 @@
         "waveLength",
         "tag"
       ],
+      "title": "LightWaveLength",
       "type": "object",
       "properties": {
         "tag": {
@@ -914,6 +928,7 @@
             "tag": { "enum": ["PredicateNoun"], "type": "string" }
           },
           "required": ["tag", "contents"],
+          "title": "PredicateNoun",
           "type": "object"
         },
         {
@@ -922,6 +937,7 @@
             "tag": { "enum": ["PredicateOmitted"], "type": "string" }
           },
           "required": ["tag", "contents"],
+          "title": "PredicateOmitted",
           "type": "object"
         }
       ]
@@ -953,6 +969,7 @@
             "tag": { "enum": ["ModifierNoun"], "type": "string" }
           },
           "required": ["tag", "contents"],
+          "title": "ModifierNoun",
           "type": "object"
         },
         {
@@ -961,6 +978,7 @@
             "tag": { "enum": ["ModifierOmitted"], "type": "string" }
           },
           "required": ["tag", "contents"],
+          "title": "ModifierOmitted",
           "type": "object"
         }
       ]
diff --git a/test/doctests.hs b/test/doctests.hs
--- a/test/doctests.hs
+++ b/test/doctests.hs
@@ -9,4 +9,4 @@
     traverse_ putStrLn args
     doctest args
   where
-    args = flags ++ ["-package-db=/nix/store/pl15d7r0mhfpygks2s8cal3jsjivwcl8-ghc-shell-for-openapi3-ghc-8.10.7-env/lib/ghc-8.10.7/package.conf.d"] ++ pkgs ++ module_sources
+    args = flags ++ pkgs ++ module_sources
