diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,6 +2,10 @@
 
 ## Unreleased changes
 
+## v0.2.2.1
+- Fix the case where types/constructors of oneofs overlap with those of
+  submessages or subenums, by appending `"'"` to the former when required.
+
 ## v0.2.2.0
 - Bump the dependency on `base` to support `ghc-8.2.1` and `Cabal-2.0`.
 - Bump the dependency for `haskell-src-exts-0.19`.
diff --git a/proto-lens-protoc.cabal b/proto-lens-protoc.cabal
--- a/proto-lens-protoc.cabal
+++ b/proto-lens-protoc.cabal
@@ -1,5 +1,5 @@
 name:                proto-lens-protoc
-version:             0.2.2.0
+version:             0.2.2.1
 synopsis:            Protocol buffer compiler for the proto-lens library.
 description:
   Turn protocol buffer files (.proto) into Haskell files (.hs) which
diff --git a/src/Data/ProtoLens/Compiler/Definitions.hs b/src/Data/ProtoLens/Compiler/Definitions.hs
--- a/src/Data/ProtoLens/Compiler/Definitions.hs
+++ b/src/Data/ProtoLens/Compiler/Definitions.hs
@@ -39,7 +39,7 @@
 import Data.String (IsString(..))
 import Data.Text (Text, cons, splitOn, toLower, uncons, unpack)
 import qualified Data.Text as T
-import Lens.Family2 ((^.), (^..))
+import Lens.Family2 ((^.), (^..), toListOf)
 import Proto.Google.Protobuf.Descriptor
     ( DescriptorProto
     , EnumDescriptorProto
@@ -214,52 +214,77 @@
   where
     protoName = protoPrefix <> d ^. name
     hsPrefix' = hsPrefix ++ hsName (d ^. name) ++ "'"
-    hsName = unpack . capitalize . camelCase
-    allFields = collectFieldsByOneofIndex (d ^. field)
+    allFields = groupFieldsByOneofIndex (d ^. field)
     thisDef =
         Message MessageInfo
             { messageName = fromString $ hsPrefix ++ hsName (d ^. name)
             , messageDescriptor = d
             , messageFields =
-                  map fieldInfo $ Map.findWithDefault [] Nothing allFields
-            , messageOneofFields =
-                  zipWith oneofInfo [0..]
-                      $ d ^.. oneofDecl . traverse . name
+                  map (fieldInfo hsPrefix')
+                      $ Map.findWithDefault [] Nothing allFields
+            , messageOneofFields = collectOneofFields hsPrefix' d allFields
             }
-    fieldInfo f = FieldInfo f $ mkFieldName $ f ^. name
-    mkFieldName n = FieldName
-                    { overloadedName = fromString n'
-                    , haskellRecordFieldName = fromString $ "_" ++ hsPrefix' ++ n'
-                    }
-      where
-        n' = fieldName n
-    oneofInfo :: Int32 -> Text -> OneofInfo
+
+fieldInfo :: String -> FieldDescriptorProto -> FieldInfo
+fieldInfo hsPrefix f = FieldInfo f $ mkFieldName hsPrefix $ f ^. name
+
+collectOneofFields
+    :: String -> DescriptorProto -> Map.Map (Maybe Int32) [FieldDescriptorProto]
+    -> [OneofInfo]
+collectOneofFields hsPrefix d allFields
+    = zipWith oneofInfo [0..] $ d ^.. oneofDecl . traverse . name
+  where
     oneofInfo idx n = OneofInfo
-                        { oneofFieldName = mkFieldName n
-                        , oneofTypeName = fromString $ hsPrefix' ++ hsName n
-                        , oneofCases = map oneofCase
-                                          $ Map.findWithDefault [] (Just idx)
-                                              allFields
-                        }
+        { oneofFieldName = mkFieldName hsPrefix n
+        , oneofTypeName = fromString $ hsPrefix ++ hsNameUnique subdefTypes n
+        , oneofCases = map oneofCase
+                          $ Map.findWithDefault [] (Just idx)
+                              allFields
+        }
     oneofCase f = OneofCase
-                        { caseField = fieldInfo f
-                        , caseConstructorName =
-                              -- Note: oneof case constructors aren't prefixed
-                              -- by the oneof name; field names (even inside
-                              -- of a oneof) are unique within a message.
-                              fromString $ hsPrefix' ++ hsName (f ^. name)
-                        }
-
+        { caseField = fieldInfo hsPrefix f
+        , caseConstructorName =
+              -- Note: oneof case constructors aren't prefixed
+              -- by the oneof name; field names (even inside
+              -- of a oneof) are unique within a message.
+              fromString $ hsPrefix ++ hsNameUnique subdefCons (f ^. name)
+        }
+    -- Make a name that doesn't overlap with those already defined by submessages
+    -- or subenums.
+    hsNameUnique ns n
+        | n' `elem` ns = n' <> "'"
+        | otherwise = n'
+      where
+        n' = hsName n
+    -- The Haskell "type" namespace
+    subdefTypes = Set.fromList $ map hsName
+                    $ toListOf (nestedType . traverse . name) d
+                    ++ toListOf (enumType . traverse . name) d
+    -- The Haskell "expression" namespace (i.e., constructors)
+    subdefCons = Set.fromList $ map hsName
+                    $ toListOf (nestedType . traverse . name) d
+                    ++ toListOf (enumType . traverse . value . traverse . name) d
 
 -- | Group fields by the index of the oneof field that they belong to.
 -- (Or 'Nothing' if they don't belong to a oneof.)
-collectFieldsByOneofIndex
+groupFieldsByOneofIndex
     :: [FieldDescriptorProto] -> Map.Map (Maybe Int32) [FieldDescriptorProto]
-collectFieldsByOneofIndex =
+groupFieldsByOneofIndex =
     fmap reverse
     . Map.fromListWith (++)
     . fmap (\f -> (f ^. maybe'oneofIndex, [f]))
 
+hsName :: Text -> String
+hsName = unpack . capitalize . camelCase
+
+mkFieldName :: String -> Text -> FieldName
+mkFieldName hsPrefix n = FieldName
+                    { overloadedName = fromString n'
+                    , haskellRecordFieldName = fromString $ "_" ++ hsPrefix ++ n'
+                    }
+      where
+        n' = fieldName n
+
 -- | Get the name in Haskell of a proto field, taking care of camel casing and
 -- clashes with language keywords.
 fieldName :: Text -> String
@@ -351,11 +376,10 @@
            -> (Map.Map Int32 Name, EnumValueInfo Name)
     helper seenNames v
         | Just n' <- Map.lookup k seenNames = (seenNames, mkValue (Just n'))
-        | otherwise = (Map.insert k hsName seenNames, mkValue Nothing)
+        | otherwise = (Map.insert k n seenNames, mkValue Nothing)
       where
-        mkValue = EnumValueInfo hsName v
-        hsName = mkHsName n
-        n = v ^. name
+        mkValue = EnumValueInfo n v
+        n = mkHsName (v ^. name)
         k = v ^. number
 
 -- Haskell types must start with an uppercase letter, so we capitalize message
