diff --git a/avro.cabal b/avro.cabal
--- a/avro.cabal
+++ b/avro.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 227dce7b3b510a3f986c3dd8ba7a73b2e32ef06ef0d81005408e20f9c8eadc2d
+-- hash: 686c91bf89cf070fdd57de52066edac6394a61472b3927e5c8fab77a5c009ba1
 
 name:           avro
-version:        0.3.6.0
+version:        0.3.6.1
 synopsis:       Avro serialization support for Haskell
 description:    Avro serialization and deserialization support for Haskell
 category:       Data
@@ -23,6 +23,7 @@
     test/data/deconflict/writer.avsc
     test/data/enums-object.json
     test/data/enums.avsc
+    test/data/internal-bindings.avsc
     test/data/karma.avsc
     test/data/logical.avsc
     test/data/maybe.avsc
diff --git a/src/Data/Avro/Schema.hs b/src/Data/Avro/Schema.hs
--- a/src/Data/Avro/Schema.hs
+++ b/src/Data/Avro/Schema.hs
@@ -27,6 +27,7 @@
   -- * Lower level utilities
   , typeName
   , buildTypeEnvironment
+  , extractBindings
   , Result(..)
   , resultToEither
 
@@ -709,22 +710,16 @@
 -- Types declared implicitly in record field definitions are also included. No distinction
 -- is made between aliases and normal names.
 extractBindings :: Type -> HashMap.HashMap TypeName Type
-extractBindings = typeBindings HashMap.empty
-  where
-    insertAll :: (Eq k, Hashable k) => [k] -> v -> HashMap.HashMap k v -> HashMap.HashMap k v
-    insertAll keys value table = foldl (\hashmap key -> HashMap.insert key value hashmap) table keys
-
-    fieldBindings :: HashMap.HashMap TypeName Type -> Field -> HashMap.HashMap TypeName Type
-    fieldBindings table Field{..} = typeBindings table fldType
-
-    typeBindings :: HashMap.HashMap TypeName Type -> Type -> HashMap.HashMap TypeName Type
-    typeBindings table t@Record{..} =
-      let withRecord = insertAll (name : aliases) t table
-      in HashMap.unions $ map (fieldBindings withRecord) fields
-    typeBindings table e@Enum{..}  = insertAll (name : aliases) e table
-    typeBindings table Union{..}   = HashMap.unions $ NE.toList $ NE.map (typeBindings table) options
-    typeBindings table f@Fixed{..} = insertAll (name : aliases) f table
-    typeBindings table _           = table
+extractBindings = \case
+  t@Record{..} ->
+    let withRecord = HashMap.fromList $ (name : aliases) `zip` repeat t
+    in HashMap.unions $ withRecord : (extractBindings . fldType <$> fields)
+  e@Enum{..}   -> HashMap.fromList $ (name : aliases) `zip` repeat e
+  Union{..}    -> HashMap.unions $ NE.toList $ extractBindings <$> options
+  f@Fixed{..}  -> HashMap.fromList $ (name : aliases) `zip` repeat f
+  Array{..}    -> extractBindings item
+  Map{..}      -> extractBindings values
+  _            -> HashMap.empty
 
 -- | Merge two schemas to produce a third.
 -- Specifically, @overlay schema reference@ fills in 'NamedTypes' in 'schema' using any matching definitions from 'reference'.
diff --git a/test/Avro/SchemaSpec.hs b/test/Avro/SchemaSpec.hs
--- a/test/Avro/SchemaSpec.hs
+++ b/test/Avro/SchemaSpec.hs
@@ -1,13 +1,17 @@
 {-# LANGUAGE DeriveGeneric       #-}
+{-# LANGUAGE OverloadedLists     #-}
 {-# LANGUAGE OverloadedStrings   #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TemplateHaskell     #-}
 module Avro.SchemaSpec
 where
 
+import qualified Data.HashMap.Lazy  as HashMap
+import qualified Data.HashSet       as HashSet
+
 import           Data.Avro
 import           Data.Avro.Deriving (makeSchema)
-import           Data.Avro.Schema   (overlay, matches)
+import           Data.Avro.Schema   (extractBindings, matches, overlay)
 
 import           Test.Hspec
 
@@ -15,6 +19,25 @@
 
 spec :: Spec
 spec = describe "Avro.SchemaSpec" $ do
+  describe "extractBindings" $
+    it "should extract bindings for all internal types" $ do
+    let schema = $(makeSchema "test/data/internal-bindings.avsc")
+        bindings = extractBindings schema
+        expected =
+          [ "InternalBindings"
+          , "InField"
+          , "NestedInField"
+          , "AliasNestedInField"
+          , "NestedEnum"
+          , "NestedFixed"
+          , "InArray"
+          , "NestedInArray"
+          , "InMap"
+          , "NestedInMap"
+          , "InUnionA"
+          , "InUnionB"
+          ]
+    HashSet.fromMap (() <$ bindings) == expected
   describe "overlay" $
     it "should support merging multiple schemas" $ do
       let expected   = $(makeSchema "test/data/overlay/expectation.avsc")
diff --git a/test/data/internal-bindings.avsc b/test/data/internal-bindings.avsc
new file mode 100644
--- /dev/null
+++ b/test/data/internal-bindings.avsc
@@ -0,0 +1,105 @@
+{
+  "name" : "InternalBindings",
+  "type" : "record",
+  "doc" : "A test record that includes subdefinitions nested in different ways.",
+  "fields" : [
+    {
+      "name" : "inField",
+      "doc" : "A record definition nested in a field of a record.",
+      "type" : {
+        "name" : "InField",
+        "type" : "record",
+        "fields" : [
+          {
+            "name" : "nestedInField",
+            "doc" : "A record definition nested in two other records.",
+            "type" : {
+              "name" : "NestedInField",
+              "type" : "record",
+              "aliases" : ["AliasNestedInField"],
+              "fields" : []
+            }
+          },
+          {
+            "name" : "nestedEnum",
+            "doc" : "An enum definition nested in a nested record.",
+            "type" : {
+              "type" : "enum",
+              "name" : "NestedEnum",
+              "symbols" : ["Foo", "Bar"]
+            }
+          },
+          {
+            "name" : "nestedFixed",
+            "doc" : "A fixed definition nested in a nested record.",
+            "type" : {
+              "type" : "fixed",
+              "size" : 42,
+              "name" : "NestedFixed"
+            }
+          }
+        ]
+      }
+    },
+    {
+      "name" : "inArray",
+      "doc" : "A record definition nested in an array type.",
+      "type" : {
+        "type" : "array",
+        "items" : {
+          "name" : "InArray",
+          "type" : "record",
+          "fields" : [
+            {
+              "name" : "nestedInArray",
+              "doc" : "A record definition nested inside a record defined in an array.",
+              "type" : {
+                "name" : "NestedInArray",
+                "type" : "record",
+                "fields" : []
+              }
+            }
+          ]
+        }
+      }
+    },
+    {
+      "name" : "inMap",
+      "doc" : "A record definition nested in a map type.",
+      "type" : {
+        "type" : "map",
+        "values" : {
+          "name" : "InMap",
+          "type" : "record",
+          "fields" : [
+            {
+              "name" : "nestedInMap",
+              "doc" : "A record definition nested inside a record defined in a map.",
+              "type" : {
+                "name" : "NestedInMap",
+                "type" : "record",
+                "fields" : []
+              }
+            }
+          ]
+        }
+      }
+    },
+    {
+      "name" : "inUnion",
+      "doc" : "Record definitions nested in a union.",
+      "type" : [
+        {
+          "name" : "InUnionA",
+          "type" : "record",
+          "fields" : []
+        },
+        {
+          "name" : "InUnionB",
+          "type" : "record",
+          "fields" : []
+        }
+      ]
+    }
+  ]
+}
