diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -144,3 +144,4 @@
 * [PADS project](https://www.cs.princeton.edu/~dpw/papers/padsml06.pdf) is another attempt to automatically infer types to treat <em>arbitrary</em> data formats (not just JSON). It mixes type declarations, with parsing/printing information in order to have a consistent view of both. It does not handle automatic type inference though.
 * [JSON Schema generator](https://www.newtonsoft.com/jsonschema/help/html/GenerateSchema.htm) uses .NET types to generate JSON Schema instead (in opposite direction.) Similar schema generation is [used here](https://sixgun.wordpress.com/2012/02/09/using-json-net-to-generate-jsonschema/)
 * Microsoft Developer Network advocates use of [Data Contracts](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-data-contracts) instead to constrain possible input data.
+* [QuickType](https://github.com/quicktype/quicktype) uses [Markov chains heuristic](https://blog.quicktype.io/markov/) instead of theory
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,9 @@
 Changelog
 =========
+    3.1.0  Apr 2020
+        * New, experimental interface for nesting
+          generated types by other code generators.
+
     3.0.5  Mar 2020
         * Using package import from `run-haskell-module` by default.
         * Expose commonly used functions for:
diff --git a/json-autotype.cabal b/json-autotype.cabal
--- a/json-autotype.cabal
+++ b/json-autotype.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: fb4adc71d7680a6ad92e8ac005c8302728f695d5a933e624e6b48ffb55d2787e
+-- hash: 69c68aeb21aa0332a50089781cb19f9fb197bb8c6d7d633af4613de8aa4dd367
 
 name:                json-autotype
-version:             3.0.5
+version:             3.1.0
 synopsis:            Automatic type declaration for JSON input data
 description:         Generates datatype declarations with Aeson''s ''Data.Aeson.FromJSON''
                      .
@@ -95,6 +95,7 @@
       Data.Aeson.AutoType.CodeGen.ElmFormat
       Data.Aeson.AutoType.CodeGen.Generic
       Data.Aeson.AutoType.CodeGen.Haskell
+      Data.Aeson.AutoType.Nested
       Data.Aeson.AutoType.Plugin.Subtype
       Paths_json_autotype
   hs-source-dirs:
diff --git a/src/Data/Aeson/AutoType/CodeGen/Haskell.hs b/src/Data/Aeson/AutoType/CodeGen/Haskell.hs
--- a/src/Data/Aeson/AutoType/CodeGen/Haskell.hs
+++ b/src/Data/Aeson/AutoType/CodeGen/Haskell.hs
@@ -8,6 +8,9 @@
   , runHaskellModule
   , runHaskellModuleStrict
   , defaultHaskellFilename
+  , importedModules
+  , requiredPackages
+  , generateModuleImports
   ) where
 
 import qualified Data.Text           as Text
@@ -49,21 +52,34 @@
 --   It was automatically generated by `json-autotype`.
 
 module |] <> capitalize moduleName <> [src| where
+|] <> generateModuleImports importedModules
 
-import           System.Exit        (exitFailure, exitSuccess)
-import           System.IO          (stderr, hPutStrLn)
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import           System.Environment (getArgs)
-import           Control.Monad      (forM_, mzero, join)
-import           Control.Applicative
-import           Data.Aeson.AutoType.Alternative
-import           Data.Aeson(eitherDecode, Value(..), FromJSON(..), ToJSON(..),
-                            pairs,
-                            (.:), (.:?), (.=), object)
-import           Data.Monoid((<>))
-import           Data.Text (Text)
-import qualified GHC.Generics
-|]
+type ModuleImport = Text
+
+generateModuleImports :: [ModuleImport] -> Text
+generateModuleImports  = Text.unlines
+                       . fmap ("import " <>)
+
+-- | List of packages required by modules below.
+--   Keep and maintain together.
+requiredPackages :: [Text]
+requiredPackages = ["aeson", "json-alt", "base", "bytestring", "text"]
+
+-- | List of modules to import
+importedModules :: [ModuleImport]
+importedModules = [
+    "          System.Exit        (exitFailure, exitSuccess)"
+  , "          System.IO          (stderr, hPutStrLn)"
+  , "qualified Data.ByteString.Lazy.Char8 as BSL"
+  , "          System.Environment (getArgs)"
+  , "          Control.Monad      (forM_, mzero, join)"
+  , "          Control.Applicative"
+  , "          Data.Aeson.AutoType.Alternative"
+  , "          Data.Aeson(eitherDecode, Value(..), FromJSON(..), ToJSON(..),pairs,(.:), (.:?), (.=), object)"
+  , "          Data.Monoid((<>))"
+  , "          Data.Text (Text)"
+  , "qualified GHC.Generics"
+  ]
 
 epilogue :: Text -> Text
 epilogue toplevelName = [src|
diff --git a/src/Data/Aeson/AutoType/Nested.hs b/src/Data/Aeson/AutoType/Nested.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/AutoType/Nested.hs
@@ -0,0 +1,98 @@
+{-# language DeriveGeneric     #-}
+{-# language OverloadedStrings #-}
+-- | Simple interface for using AutoType inference
+--   in other code generators.
+--
+--   Simply takes a list of Aeson values,
+--   and returns a type description.
+--
+--   For this type description,
+--   we can use function to generate an entire new module.
+--
+--   Note that while we can put more code in the module,
+--   it is recommended to avoid multiple automatically
+--   generated types in order to avoid name conflicts.
+module Data.Aeson.AutoType.Nested(
+    defaultImportedModules
+  , generateModuleImports
+  , inferType
+  , CodeFragment
+  , TypeName
+  , DeclaredType(..)
+  ) where
+
+import Data.Aeson
+import Data.Aeson.AutoType.CodeGen.Haskell(generateModuleImports, requiredPackages, importedModules)
+import Data.Aeson.AutoType.CodeGen.HaskellFormat(displaySplitTypes)
+import Data.Aeson.AutoType.Extract(extractType, unifyTypes)
+import Data.Aeson.AutoType.Split(splitTypeByLabel)
+import Data.Default
+import Data.Typeable
+import Data.Text(Text)
+import GHC.Generics
+
+-- FIXME: general type to compose generated types
+-- move to JSON Autotype as library interface?
+-- * API Response Structures
+type CodeFragment   = Text
+type TypeName       = Text
+type ImportedModule = Text
+type PackageName    = Text
+
+-- | Type declaration and its requirements
+--   Content to embed in an autogenerated module:
+--   * name of the type to reference
+--   * declarations to describe it
+--   * module imports necessary for declarations
+--     to work
+data DeclaredType = DeclaredType
+  {
+    -- | Code fragment to be inserted in generated module
+    typeCodeFragment    ::  CodeFragment
+    -- | Toplevel type name to refer to
+  , typeName            ::  TypeName
+    -- | List of clauses to add to imports list
+  , typeImportedModules :: [ImportedModule]
+    -- | List of packages to add to generated package dependencies
+  , typePackages        :: [PackageName]
+  }
+  deriving
+    ( Eq
+    , Show
+    , Generic
+    , Typeable
+    )
+
+
+instance Default DeclaredType where
+  -- Minimal placeholder to use in case we cannot infer proper type
+  def = DeclaredType {
+            typeCodeFragment    =  ""
+          , typeName            =  "Data.Aeson.Value"
+          , typeImportedModules = ["qualified Data.Aeson"]
+          , typePackages        = ["aeson"]
+          }
+
+-- | List of modules imported for Autotyped declarations
+defaultImportedModules = importedModules
+
+-- | Given intended type name, and a list of
+--   text fields with JSON, return
+--   either an error, or an `EndpointResponse`
+--   that allows to declare and use this type
+--   in generated module.
+inferType :: Text -> [Value] -> DeclaredType
+inferType typeName []         = def
+inferType typeName jsonValues =
+    DeclaredType {
+          typeImportedModules = defaultImportedModules
+        , typeCodeFragment    = displaySplitTypes splitTypeDescriptors
+        , typeName            = typeName
+        , typePackages        = requiredPackages
+        }
+  where
+    valueTypes           = map extractType jsonValues
+    -- FIXME: should be <> in Typelike?
+    unifiedType          = foldr1 unifyTypes valueTypes
+    splitTypeDescriptors = splitTypeByLabel typeName unifiedType
+
diff --git a/src/Data/Aeson/AutoType/Split.hs b/src/Data/Aeson/AutoType/Split.hs
--- a/src/Data/Aeson/AutoType/Split.hs
+++ b/src/Data/Aeson/AutoType/Split.hs
@@ -62,7 +62,8 @@
 splitTypeByLabel' _  TDouble   = return TDouble
 splitTypeByLabel' _  TBool     = return TBool
 splitTypeByLabel' _  TNull     = return TNull
-splitTypeByLabel' _ (TLabel r) = assert False $ return $ TLabel r -- unnecessary?
+splitTypeByLabel' _ (TLabel r) = error $ "Splitting into labelled types after label "
+                                      <> show r <> " was already given!"
 splitTypeByLabel' l (TUnion u) = do m <- mapM (splitTypeByLabel' l) $ Set.toList u
                                     return $! TUnion $! Set.fromList m
 splitTypeByLabel' l (TArray a) = do m <- splitTypeByLabel' (l `Text.append` "Elt") a
