diff --git a/IO.hs b/IO.hs
--- a/IO.hs
+++ b/IO.hs
@@ -7,27 +7,27 @@
     , parseASTFile
     , parseNamespaceMappings
     , parseAliasMappings
+    , slashNormalize
     )
     where
 
-import System.Exit
-import System.FilePath
-import System.Directory
-import System.IO
 import Control.Applicative
-import Prelude
-import Data.Aeson (eitherDecode)
-import Data.Text
 import Control.Monad.Loops (firstM)
+import Data.Aeson (eitherDecode)
+import Data.Void (Void)
 import qualified Data.ByteString.Lazy as BL
-import Text.Parsec
-import Text.ParserCombinators.Parsec.Error
-import Text.Printf
-import Language.Bond.Syntax.Types (Bond(..))
-import Language.Bond.Syntax.JSON()
-import Language.Bond.Parser
+import qualified Data.Text as T
 import Language.Bond.Codegen.TypeMapping
-
+import Language.Bond.Parser
+import Language.Bond.Syntax.JSON()
+import Language.Bond.Syntax.Types (Bond(..))
+import Prelude
+import System.Directory
+import System.Exit
+import System.FilePath
+import System.IO
+import Text.Megaparsec
+import Text.Printf
 
 parseFile :: [FilePath] -> FilePath -> IO(Bond)
 parseFile importDirs file =
@@ -53,9 +53,10 @@
             Just path' -> do
                 content <- readFileUtf8 path'
                 return (path', content)
-            Nothing -> fail $ "Can't find import file " ++ importFile
+            Nothing -> fail $ "Can't find import file " ++ importFile'
       where
-        findFilePath dirs = fmap (</> importFile) <$> firstM (doesFileExist . (</> importFile)) dirs
+        importFile' = slashNormalize importFile
+        findFilePath dirs = fmap (</> importFile') <$> firstM (doesFileExist . (</> importFile')) dirs
 
     readFileUtf8 name = do
         h <- openFile name ReadMode
@@ -86,21 +87,30 @@
         Left err -> fail $ show err
         Right m -> return m
 
-msbuildErrorMessage :: ParseError -> String
+msbuildErrorMessage :: (ParseErrorBundle String Void) -> String
 msbuildErrorMessage err = printf "%s(%d,%d) : error B0000: %s" name line col message
     where
         message = combinedMessage err
-        pos = errorPos err
+        pos = pstateSourcePos . bundlePosState $ err
         name = sourceName pos
-        line = sourceLine pos
-        col = sourceColumn pos
+        line = unPos $ sourceLine pos
+        col = unPos $ sourceColumn pos
 
-combinedMessage :: ParseError -> String
-combinedMessage err = id $ unpack $ intercalate (pack ", ") messages
+combinedMessage :: (ParseErrorBundle String Void) -> String
+combinedMessage err = id $ T.unpack $ T.intercalate (T.pack ", ") messages
     where
-        -- showErrorMessages returns a multi-line String starting with a blank
-        -- line. We need to break it up to make a useful one-line message.
-        messages = splitOn (pack "\n") $ strip $ pack $
-            showErrorMessages "or" "unknown parse error"
-                "expecting" "unexpected" "end of input"
-                (errorMessages err)
+        -- parseErrorPretty returns a multi-line String.
+        -- We need to break it up to make a useful one-line message.
+        messages = T.splitOn (T.pack "\n") $ T.strip $ T.pack $ errorBundlePretty err
+
+-- | Normalizes a file path to only use the current platform's preferred
+-- directory separator.
+--
+-- Bond doesn't support files or directories with backslashes in their
+-- names, so backslashes are always converted to the platform's preferred
+-- separator.
+slashNormalize :: FilePath -> FilePath
+slashNormalize path = map replace path
+  where replace '/'  = pathSeparator
+        replace '\\' = pathSeparator
+        replace c    = c
diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -6,13 +6,16 @@
 import System.Environment (getArgs, withArgs)
 import System.Directory
 import System.FilePath
+import Data.Maybe
 import Data.Monoid
+import qualified Data.Foldable as F
 import Control.Monad
 import Prelude
 import Control.Concurrent.Async
 import GHC.Conc (getNumProcessors, setNumCapabilities)
 import Data.Text.Lazy (Text)
-import qualified Data.Text.Lazy.IO as L
+import qualified Data.Text.Lazy as LT
+import qualified Data.Text.Lazy.IO as LTIO
 import Data.Aeson (encode)
 import qualified Data.ByteString.Lazy as BL
 import Language.Bond.Syntax.Types (Bond(..), Declaration(..), Import, Type(..))
@@ -29,11 +32,12 @@
 main :: IO()
 main = do
     args <- getArgs
-    options <- (if null args then withArgs ["--help"] else id) getOptions
+    options <- (if null args then withArgs ["--help=all"] else id) getOptions
     setJobs $ jobs options
     case options of
         Cpp {..}    -> cppCodegen options
         Cs {..}     -> csCodegen options
+        Java {..}   -> javaCodegen options
         Schema {..} -> writeSchema options
         _           -> print options
 
@@ -50,6 +54,12 @@
 concurrentlyFor_ = (void .) . flip mapConcurrently
 
 
+createDir :: FilePath -> IO ()
+createDir path = do
+    -- recursive = True
+    createDirectoryIfMissing True path
+
+
 writeSchema :: Options -> IO()
 writeSchema Schema {..} =
     concurrentlyFor_ files $ \file -> do
@@ -68,42 +78,58 @@
 
 cppCodegen :: Options -> IO()
 cppCodegen options@Cpp {..} = do
-    let typeMapping = maybe cppTypeMapping cppCustomAllocTypeMapping allocator
-    concurrentlyFor_ files $ codeGen options typeMapping $
-        [ reflection_h
-        , types_cpp
-        , types_comm_cpp
-        , types_h header enum_header allocator
-        , apply_h applyProto apply_attribute
-        , apply_cpp applyProto
-        , comm_h
-        ] <>
-        [ enum_h | enum_header]
+    let typeMappingAliases = maybe cppTypeMapping (cppCustomAllocTypeMapping scoped_alloc_enabled) allocator
+    let typeMapping = if type_aliases_enabled then typeMappingAliases else cppExpandAliasesTypeMapping typeMappingAliases
+    concurrentlyFor_ files $ codeGen options typeMapping templates
   where
     applyProto = map snd $ filter (enabled apply) protocols
     enabled a p = null a || fst p `elem` a
     protocols =
-        [ (Compact, Protocol " ::bond::CompactBinaryReader< ::bond::InputBuffer>"
-                             " ::bond::CompactBinaryWriter< ::bond::OutputBuffer>")
-        , (Fast,    Protocol " ::bond::FastBinaryReader< ::bond::InputBuffer>"
-                             " ::bond::FastBinaryWriter< ::bond::OutputBuffer>")
-        , (Simple,  Protocol " ::bond::SimpleBinaryReader< ::bond::InputBuffer>"
-                             " ::bond::SimpleBinaryWriter< ::bond::OutputBuffer>")
+        [ (Compact, ProtocolReader " ::bond::CompactBinaryReader<::bond::InputBuffer>")
+        , (Compact, ProtocolWriter " ::bond::CompactBinaryWriter<::bond::OutputBuffer>")
+        , (Compact, ProtocolWriter " ::bond::CompactBinaryWriter<::bond::OutputBuffer>::Pass0")
+        , (Fast,    ProtocolReader " ::bond::FastBinaryReader<::bond::InputBuffer>")
+        , (Fast,    ProtocolWriter " ::bond::FastBinaryWriter<::bond::OutputBuffer>")
+        , (Simple,  ProtocolReader " ::bond::SimpleBinaryReader<::bond::InputBuffer>")
+        , (Simple,  ProtocolWriter " ::bond::SimpleBinaryWriter<::bond::OutputBuffer>")
         ]
+    templates = concat $ map snd $ filter fst codegen_templates
+    codegen_templates = [ (core_enabled, core_files) ]
+    core_files = [
+          reflection_h export_attribute
+        , types_h export_attribute header enum_header allocator alloc_ctors_enabled type_aliases_enabled scoped_alloc_enabled
+        , types_cpp
+        , apply_h applyProto export_attribute
+        , apply_cpp applyProto
+        ] <>
+        [ enum_h | enum_header]
 cppCodegen _ = error "cppCodegen: impossible happened."
 
 csCodegen :: Options -> IO()
 csCodegen options@Cs {..} = do
-    let fieldMapping = if readonly_properties
+    concurrentlyFor_ files $ codeGen options typeMapping templates
+  where
+    typeMapping = if collection_interfaces
+            then csCollectionInterfacesTypeMapping
+            else csTypeMapping
+    fieldMapping = if readonly_properties
             then ReadOnlyProperties
             else if fields
                  then PublicFields
                  else Properties
-    let typeMapping = if collection_interfaces then csCollectionInterfacesTypeMapping else csTypeMapping
-    let templates = [ comm_interface_cs , comm_proxy_cs , comm_service_cs , types_cs Class fieldMapping ]
-    concurrentlyFor_ files $ codeGen options typeMapping templates
+    constructorOptions = if constructor_parameters
+            then ConstructorParameters
+            else DefaultWithProtectedBase
+    templates = concat $ map snd $ filter fst codegen_templates
+    codegen_templates = [ (structs_enabled, [types_cs Class fieldMapping constructorOptions]) ]
 csCodegen _ = error "csCodegen: impossible happened."
 
+anyServiceInheritance :: [Declaration] -> Bool
+anyServiceInheritance = getAny . F.foldMap serviceWithBase
+  where
+    serviceWithBase Service{..} = Any $ isJust serviceBase
+    serviceWithBase _ = Any False
+
 codeGen :: Options -> TypeMapping -> [Template] -> FilePath -> IO ()
 codeGen options typeMapping templates file = do
     let outputDir = output_dir options
@@ -112,9 +138,57 @@
     namespaceMapping <- parseNamespaceMappings $ namespace options
     (Bond imports namespaces declarations) <- parseFile (import_dir options) file
     let mappingContext = MappingContext typeMapping aliasMapping namespaceMapping namespaces
-    forM_ templates $ \template -> do
-        let (suffix, code) = template mappingContext baseName imports declarations
-        let fileName = baseName ++ suffix
-        createDirectoryIfMissing True outputDir
-        let content = if (no_banner options) then code else (commonHeader "//" fileName <> code)
-        L.writeFile (outputDir </> fileName) content
+    case (anyServiceInheritance declarations, service_inheritance_enabled options) of
+        (True, False)   -> fail "Use --enable-service-inheritance to enable service inheritance syntax."
+        _                     -> forM_ templates $ \template -> do
+                                    let (suffix, code) = template mappingContext baseName imports declarations
+                                    let fileName = baseName ++ suffix
+                                    createDirectoryIfMissing True outputDir
+                                    let content = if (no_banner options) then code else (commonHeader "//" file fileName <> code)
+                                    LTIO.writeFile (outputDir </> fileName) content
+
+-- Java's class-per-file and package-as-path requirements make it difficult to
+-- share code with languages where there is a known set of generated files for
+-- each bondfile.
+javaCodegen :: Options -> IO ()
+javaCodegen Java {..} = do
+    namespaceMapping <- parseNamespaceMappings namespace
+
+    concurrentlyFor_ files $ \bondFile -> do
+        (Bond imports namespaces declarations) <- parseFile import_dir bondFile
+        -- AliasMappings not implemented.
+        let mappingContext = MappingContext javaTypeMapping [] namespaceMapping namespaces
+
+        forM_ declarations $ \declaration -> do
+            let javaNamespace = getDeclNamespace mappingContext declaration
+            let packageDir =
+                  output_dir </> case javaNamespace of
+                    x:xs -> foldl (</>) x xs
+                    []   -> error "declaration " ++ declName declaration ++  " has no namespace"
+            let javaFile = declName declaration ++ ".java"
+
+            let code = case declaration of
+                  Struct {} -> class_java mappingContext imports declaration
+                  Enum {}   -> enum_java mappingContext declaration
+                  _         -> mempty
+
+            if LT.null code
+                then return ()
+                else do
+                    let content =
+                          if no_banner
+                          then code
+                          else (commonHeader "//" safeBondFile safeJavaFile <> code)
+                              where
+                                  -- javac will always treat "\u" as the start
+                                  -- of a unicode escape sequence, and will
+                                  -- error out if it isn't followed by a valid
+                                  -- code. This breaks compilation of generated
+                                  -- code if either path has components that
+                                  -- start with u.
+                                  safeBondFile = slashForward bondFile
+                                  safeJavaFile = slashForward javaFile
+
+                    createDir packageDir
+                    LTIO.writeFile (packageDir </> javaFile) content
+javaCodegen _ = error "javaCodegen: impossible happened."
diff --git a/Options.hs b/Options.hs
--- a/Options.hs
+++ b/Options.hs
@@ -1,7 +1,7 @@
 -- Copyright (c) Microsoft. All rights reserved.
 -- Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
-{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveDataTypeable, RecordWildCards #-}
 {-# OPTIONS_GHC -fno-warn-missing-fields #-}
 {-# OPTIONS_GHC -fno-cse #-}
 
@@ -16,6 +16,7 @@
 import Data.Version (showVersion)
 import System.Console.CmdArgs
 import System.Console.CmdArgs.Explicit (processValue)
+import IO (slashNormalize)
 
 data ApplyOptions =
     Compact |
@@ -35,9 +36,14 @@
         , enum_header :: Bool
         , allocator :: Maybe String
         , apply :: [ApplyOptions]
-        , apply_attribute :: Maybe String
+        , export_attribute :: Maybe String
         , jobs :: Maybe Int
         , no_banner :: Bool
+        , core_enabled :: Bool
+        , alloc_ctors_enabled :: Bool
+        , type_aliases_enabled :: Bool
+        , scoped_alloc_enabled :: Bool
+        , service_inheritance_enabled :: Bool
         }
     | Cs
         { files :: [FilePath]
@@ -50,13 +56,26 @@
         , fields :: Bool
         , jobs :: Maybe Int
         , no_banner :: Bool
+        , structs_enabled :: Bool
+        , service_inheritance_enabled :: Bool
+        , constructor_parameters :: Bool
         }
+    | Java
+        { files :: [FilePath]
+        , import_dir :: [FilePath]
+        , output_dir :: FilePath
+        , using :: [String]
+        , namespace :: [String]
+        , jobs :: Maybe Int
+        , no_banner :: Bool
+        }
     | Schema
         { files :: [FilePath]
         , import_dir :: [FilePath]
         , output_dir :: FilePath
         , jobs :: Maybe Int
         , runtime_schema :: Bool
+        , service_inheritance_enabled :: Bool
         }
       deriving (Show, Data, Typeable)
 
@@ -71,9 +90,14 @@
     , enum_header = def &= name "e" &= help "Generate enums into a separate header file"
     , allocator = def &= typ "ALLOCATOR" &= help "Generate types using the specified  allocator"
     , apply = def &= typ "PROTOCOL" &= help "Generate Apply function overloads for the specified protocol only; supported protocols: compact, fast and simple"
-    , apply_attribute = def &= typ "ATTRIBUTE" &= help "Prefix the declarations of Apply functions with the specified C++ attribute/declspec"
+    , export_attribute = def &= typ "ATTRIBUTE" &= explicit &= name "apply-attribute" &= name "export-attribute" &= help "Prefix declarations for library export with the specified C++ attribute/declspec. apply-attribute is a deprecated synonym."
     , jobs = def &= opt "0" &= typ "NUM" &= name "j" &= help "Run NUM jobs simultaneously (or '$ncpus' if no NUM is not given)"
     , no_banner = def &= help "Omit the banner at the top of generated files"
+    , core_enabled = True &= explicit &= name "core" &= help "Generate core serialization definitions (true by default, --core=false to disable)"
+    , alloc_ctors_enabled = False &= explicit &= name "alloc-ctors" &= help "Generate constructors with allocator argument"
+    , type_aliases_enabled = False &= explicit &= name "type-aliases" &= help "Generate type aliases"
+    , scoped_alloc_enabled = False &= explicit &= name "scoped-alloc" &= help "Use std::scoped_allocator_adaptor for strings and containers"
+    , service_inheritance_enabled = False &= explicit &= name "enable-service-inheritance" &= help "Enable service inheritance syntax in IDL"
     } &=
     name "c++" &=
     help "Generate C++ code"
@@ -83,10 +107,19 @@
     { collection_interfaces = def &= name "c" &= help "Use interfaces rather than concrete collection types"
     , readonly_properties = def &= name "r" &= help "Generate private property setters"
     , fields = def &= name "f" &= help "Generate public fields rather than properties"
+    , structs_enabled = True &= explicit &= name "structs" &= help "Generate C# types for Bond structs and enums (true by default, use \"--structs=false\" to disable)"
+    , constructor_parameters = def &= explicit &= name "preview-constructor-parameters" &= help "PREVIEW FEATURE: Generate a constructor that takes all the fields as parameters. Typically used with readonly-properties."
     } &=
     name "c#" &=
     help "Generate C# code"
 
+java :: Options
+java = Java
+    { using = def &= typ "MAPPING" &= name "u" &= help "Currently unimplemented and ignored for Java"
+    } &=
+    name "java" &=
+    help "Generate Java code"
+
 schema :: Options
 schema = Schema
     { runtime_schema = def &= help "Generate Simple JSON representation of runtime schema, aka SchemaDef"
@@ -94,15 +127,30 @@
     name "schema" &=
     help "Output the JSON representation of the schema"
 
+slashNormalizeOption :: Options -> Options
+slashNormalizeOption Options = Options
+slashNormalizeOption o@Cpp{..}    = o { files = map slashNormalize files,
+                                        import_dir = map slashNormalize import_dir,
+                                        output_dir = slashNormalize output_dir }
+slashNormalizeOption o@Cs{..}     = o { files = map slashNormalize files,
+                                        import_dir = map slashNormalize import_dir,
+                                        output_dir = slashNormalize output_dir }
+slashNormalizeOption o@Java{..}   = o { files = map slashNormalize files,
+                                        import_dir = map slashNormalize import_dir,
+                                        output_dir = slashNormalize output_dir }
+slashNormalizeOption o@Schema{..} = o { files = map slashNormalize files,
+                                        import_dir = map slashNormalize import_dir,
+                                        output_dir = slashNormalize output_dir }
+                                   
 
 mode :: Mode (CmdArgs Options)
-mode = cmdArgsMode $ modes [cpp, cs, schema] &=
+mode = cmdArgsMode $ modes [cpp, cs, java, schema] &=
     program "gbc" &=
     help "Compile Bond schema file(s) and generate specified output. The schema file(s) can be in one of two formats: Bond IDL or JSON representation of the schema abstract syntax tree as produced by `gbc schema`. Multiple schema files can be specified either directly on the command line or by listing them in a text file passed to gbc via @listfile syntax." &=
     summary ("Bond Compiler " ++ showVersion version ++ ", (C) Microsoft")
 
 getOptions :: IO Options
-getOptions = cmdArgsRun mode
+getOptions = slashNormalizeOption <$> cmdArgsRun mode
 
 processOptions :: [String] -> Options
 processOptions = cmdArgsValue . processValue mode
diff --git a/bond.cabal b/bond.cabal
--- a/bond.cabal
+++ b/bond.cabal
@@ -1,121 +1,162 @@
--- Copyright (c) Microsoft. All rights reserved.
--- Licensed under the MIT license. See LICENSE file in the project root for full license information.
+cabal-version: 1.12
 
-name:               bond
-version:            0.7.0.0
-cabal-version:      >= 1.8
-tested-with:        GHC>=7.4.1
-synopsis:           Bond schema compiler and code generator
-description:        Bond is a cross-platform framework for handling schematized
-                    data. It supports cross-language de/serialization and
-                    powerful generic mechanisms for efficiently manipulating
-                    data.
-                    .
-                    This package contains a library for parsing the Bond
-                    schema definition language and performing template-based
-                    code generation. The library includes built-in templates
-                    for generating standard Bond C++ and C# code, as well as
-                    utilities for writing custom codegen templates.
-                    .
-                    The package also contains a command-line compiler/codegen
-                    tool, named gbc, which is primarily used to generate code
-                    for C++ and C# programs using Bond.
+-- This file has been generated from package.yaml by hpack version 0.35.0.
+--
+-- see: https://github.com/sol/hpack
 
-homepage:           https://github.com/Microsoft/bond
-license:            MIT
-license-file:       LICENSE
-author:             Adam Sapek <adamsap@microsoft.com>
-maintainer:         Adam Sapek <adamsap@microsoft.com>
-bug-reports:        https://github.com/Microsoft/bond/issues
-copyright:          Copyright (c) Microsoft. All rights reserved.
-category:           Language, Compiler, Code Generation
-build-type:         Simple
+name:           bond
+version:        0.13.0.0
+synopsis:       Bond schema compiler and code generator
+description:    Bond is a cross-platform framework for handling schematized data. It supports cross-language de/serialization and powerful generic mechanisms for efficiently manipulating data. . This package contains a library for parsing the Bond schema definition language and performing template-based code generation. The library includes built-in templates for generating standard Bond C++ and C# code, as well as utilities for writing custom codegen templates. . The package also contains a command-line compiler/codegen tool, named gbc, which is primarily used to generate code for C++ and C# programs using Bond.
+category:       Language, Compiler, Code Generation
+homepage:       https://github.com/microsoft/bond#readme
+bug-reports:    https://github.com/microsoft/bond/issues
+author:         Adam Sapek <adamsap@microsoft.com>
+maintainer:     Bond Development Team <bond-dev@microsoft.com>
+copyright:      Copyright (c) Microsoft. All rights reserved.
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
 
 source-repository head
-  type:             git
-  location:         git@github.com:Microsoft/bond.git
+  type: git
+  location: https://github.com/microsoft/bond
 
-library
-  hs-source-dirs:   src
-  build-depends:    aeson >= 0.7.0.6 && < 0.12.0.0,
-                    base >= 4.5 && < 5,
-                    bytestring >= 0.10,
-                    filepath >= 1.0,
-                    mtl >= 2.1,
-                    parsec >= 3.1,
-                    scientific >= 0.3.4.6,
-                    shakespeare >= 2.0,
-                    text >= 0.11
-  ghc-options:      -Wall
-  exposed-modules:  Language.Bond.Parser
-                    Language.Bond.Util
-                    Language.Bond.Syntax.Types
-                    Language.Bond.Syntax.JSON
-                    Language.Bond.Syntax.Util
-                    Language.Bond.Syntax.SchemaDef
-                    Language.Bond.Codegen.Util
-                    Language.Bond.Codegen.TypeMapping
-                    Language.Bond.Codegen.Templates
-  other-modules:    Language.Bond.Codegen.CustomMapping
-                    Language.Bond.Codegen.Cpp.Apply_cpp
-                    Language.Bond.Codegen.Cpp.Apply_h
-                    Language.Bond.Codegen.Cpp.Enum_h
-                    Language.Bond.Codegen.Cpp.Reflection_h
-                    Language.Bond.Codegen.Cpp.Types_cpp
-                    Language.Bond.Codegen.Cpp.Types_Comm_cpp
-                    Language.Bond.Codegen.Cpp.Types_h
-                    Language.Bond.Codegen.Cpp.Comm_h
-                    Language.Bond.Codegen.Cs.Types_cs
-                    Language.Bond.Codegen.Cs.Comm_cs
-                    Language.Bond.Codegen.Cpp.ApplyOverloads
-                    Language.Bond.Codegen.Cpp.Util
-                    Language.Bond.Codegen.Cs.Util
-                    Language.Bond.Lexer
-                    Language.Bond.Syntax.Internal
-                    Paths_bond
+flag warningsAsErrors
+  description: Treat warnings as errors for building bond
+  manual: True
+  default: False
 
-test-suite gbc-tests
-  type:             exitcode-stdio-1.0
-  hs-source-dirs:   tests, .
-  main-is:          Main.hs
-  other-modules:    Tests.Codegen
-                    Tests.Syntax
-  ghc-options:      -threaded -Wall
-  build-depends:    bond,
-                    aeson >= 0.7.0.6 && < 0.12.0.0,
-                    aeson-pretty == 0.7.2,
-                    base >= 4.5 && < 5,
-                    bytestring >= 0.10,
-                    cmdargs >= 0.10.10,
-                    directory >= 1.1,
-                    filepath >= 1.0,
-                    monad-loops >= 0.4,
-                    text >= 0.11,
-                    derive,
-                    HUnit,
-                    QuickCheck,
-                    Diff >= 0.2 && < 0.4,
-                    pretty,
-                    tasty,
-                    tasty-golden,
-                    tasty-hunit,
-                    tasty-quickcheck,
-                    parsec >= 3.1
+library
+  exposed-modules:
+      Language.Bond.Codegen.Cpp.Apply_cpp
+      Language.Bond.Codegen.Cpp.Apply_h
+      Language.Bond.Codegen.Cpp.ApplyOverloads
+      Language.Bond.Codegen.Cpp.Enum_h
+      Language.Bond.Codegen.Cpp.Reflection_h
+      Language.Bond.Codegen.Cpp.Types_cpp
+      Language.Bond.Codegen.Cpp.Types_h
+      Language.Bond.Codegen.Cpp.Util
+      Language.Bond.Codegen.Cs.Types_cs
+      Language.Bond.Codegen.Cs.Util
+      Language.Bond.Codegen.CustomMapping
+      Language.Bond.Codegen.Java.Class_java
+      Language.Bond.Codegen.Java.Enum_java
+      Language.Bond.Codegen.Java.Util
+      Language.Bond.Codegen.Templates
+      Language.Bond.Codegen.TypeMapping
+      Language.Bond.Codegen.Util
+      Language.Bond.Lexer
+      Language.Bond.Parser
+      Language.Bond.Syntax.Internal
+      Language.Bond.Syntax.JSON
+      Language.Bond.Syntax.SchemaDef
+      Language.Bond.Syntax.Types
+      Language.Bond.Syntax.Util
+      Language.Bond.Util
+  other-modules:
+      Paths_bond
+  hs-source-dirs:
+      src
+  build-depends:
+      aeson
+    , base >=4.7 && <5
+    , bytestring
+    , filepath
+    , megaparsec
+    , mtl
+    , scientific
+    , shakespeare
+    , text
+    , unordered-containers
+  default-language: Haskell2010
+  if os(windows) && arch(i386)
+    ld-options: -Wl,--dynamicbase -Wl,--nxcompat -Wl,--large-address-aware
+  if os(windows) && arch(x86_64)
+    ld-options: -Wl,--dynamicbase -Wl,--nxcompat -Wl,--high-entropy-va
+  if flag(warningsAsErrors)
+    ghc-options: -Wall -Werror
 
 executable gbc
-  main-is:          Main.hs
-  other-modules:    IO
-                    Options
-  ghc-options:      -threaded -Wall
-  build-depends:    bond,
-                    aeson >= 0.7.0.6 && < 0.12.0.0,
-                    async >= 2.0.1.0,
-                    base >= 4.5 && < 5,
-                    bytestring >= 0.10,
-                    cmdargs >= 0.10.10,
-                    process < 1.5,
-                    directory >= 1.1,
-                    filepath >= 1.0,
-                    monad-loops >= 0.4,
-                    text >= 0.11,
-                    parsec >= 3.1
+  main-is: Main.hs
+  other-modules:
+      IO
+      Options
+      Paths_bond
+  hs-source-dirs:
+      ./
+  build-depends:
+      aeson
+    , async
+    , base
+    , bond
+    , bytestring
+    , cmdargs
+    , directory
+    , filepath
+    , megaparsec
+    , monad-loops
+    , mtl
+    , process
+    , scientific
+    , shakespeare
+    , text
+    , unordered-containers
+  default-language: Haskell2010
+  if os(windows) && arch(i386)
+    ld-options: -Wl,--dynamicbase -Wl,--nxcompat -Wl,--large-address-aware
+  if os(windows) && arch(x86_64)
+    ld-options: -Wl,--dynamicbase -Wl,--nxcompat -Wl,--high-entropy-va
+  if flag(warningsAsErrors)
+    ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall -Werror
+  else
+    ghc-options: -threaded -rtsopts -with-rtsopts=-N
+
+test-suite gbc-tests
+  type: exitcode-stdio-1.0
+  main-is: TestMain.hs
+  other-modules:
+      Tests.Codegen
+      Tests.Codegen.Util
+      Tests.Syntax
+      Tests.Syntax.JSON
+      Paths_bond
+      IO
+      Options
+  hs-source-dirs:
+      tests
+      ./
+  build-depends:
+      Diff
+    , HUnit
+    , QuickCheck
+    , aeson
+    , aeson-pretty
+    , base
+    , bond
+    , bytestring
+    , cmdargs
+    , directory
+    , filepath
+    , megaparsec
+    , monad-loops
+    , mtl
+    , pretty
+    , quickcheck-arbitrary-template
+    , scientific
+    , shakespeare
+    , tasty
+    , tasty-golden
+    , tasty-hunit
+    , tasty-quickcheck
+    , text
+    , unordered-containers
+  default-language: Haskell2010
+  if os(windows) && arch(i386)
+    ld-options: -Wl,--dynamicbase -Wl,--nxcompat -Wl,--large-address-aware
+  if os(windows) && arch(x86_64)
+    ld-options: -Wl,--dynamicbase -Wl,--nxcompat -Wl,--high-entropy-va
+  if flag(warningsAsErrors)
+    ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall -Werror
+  else
+    ghc-options: -threaded -rtsopts -with-rtsopts=-N
diff --git a/src/Language/Bond/Codegen/Cpp/ApplyOverloads.hs b/src/Language/Bond/Codegen/Cpp/ApplyOverloads.hs
--- a/src/Language/Bond/Codegen/Cpp/ApplyOverloads.hs
+++ b/src/Language/Bond/Codegen/Cpp/ApplyOverloads.hs
@@ -16,53 +16,64 @@
 -- | Protocol data type is used to specify what protocols the @Apply@ function
 -- overloads should be generated for.
 data Protocol =
-    Protocol
-    { protocolReader :: String -- ^ Name of the class implementing the protocol reader.
-    , protocolWriter :: String -- ^ Name of the class implementing the protocol writer.
-    }
+    ProtocolReader String | -- ^ Name of the class implementing the protocol reader.
+    ProtocolWriter String   -- ^ Name of the class implementing the protocol writer.
 
 
 -- Apply overloads
 applyOverloads :: [Protocol] -> MappingContext -> Text -> Text -> Declaration -> Text
-applyOverloads protocols cpp attr body s@Struct {..} | null declParams = [lt|
+applyOverloads protocols cpp attr extern s@Struct {..} | null declParams = [lt|
     //
-    // Overloads of Apply function with common transforms for #{declName}.
-    // These overloads will be selected using argument dependent lookup
-    // before ::bond::Apply function templates.
+    // Extern template specializations of Apply function with common
+    // transforms for #{declName}.
     //
-    #{attr}bool Apply(const ::bond::To< #{qualifiedName}>& transform,
-               const ::bond::bonded< #{qualifiedName}>& value)#{body}
 
-    #{attr}bool Apply(const ::bond::InitSchemaDef& transform,
-               const #{qualifiedName}& value)#{body}
+    #{extern}template #{attr}
+    bool Apply(const ::bond::To< #{qualifiedName}>& transform,
+               const ::bond::bonded< #{qualifiedName}>& value);
+
+    #{extern}template #{attr}
+    bool Apply< #{qualifiedName}>(const ::bond::InitSchemaDef& transform);
+
+    #{extern}template #{attr}
+    bool Apply(const ::bond::Null& transform,
+               const ::bond::bonded< #{qualifiedName}, ::bond::SimpleBinaryReader< ::bond::InputBuffer>&>& value);
     #{newlineSep 1 applyOverloads' protocols}|]
   where
     qualifiedName = getDeclTypeName cpp s
 
-    applyOverloads' p = [lt|#{deserialization p}
-    #{serialization serializer p}
-    #{serialization marshaler p}|]
+    applyOverloads' p = [lt|#{deserialization p}#{newlineSep 1 (serialization p) serializingTransforms}|]
 
-    serializer = "Serializer" :: String
-    marshaler = "Marshaler" :: String
+    serializingTransforms =
+        [ [lt|Serializer|]
+        , [lt|Marshaler|]
+        ]
 
-    deserialization Protocol {..} = [lt|
-    #{attr}bool Apply(const ::bond::To< #{qualifiedName}>& transform,
-               const ::bond::bonded< #{qualifiedName}, #{protocolReader}&>& value)#{body}
+    deserialization (ProtocolWriter _) = mempty
+    deserialization (ProtocolReader protocolReader) = [lt|
+    #{extern}template #{attr}
+    bool Apply(const ::bond::To< #{qualifiedName}>& transform,
+               const ::bond::bonded< #{qualifiedName}, #{protocolReader}&>& value);
 
-    #{attr}bool Apply(const ::bond::To< #{qualifiedName}>& transform,
-               const ::bond::bonded<void, #{protocolReader}&>& value)#{body}|]
+    #{extern}template #{attr}
+    bool Apply(const ::bond::To< #{qualifiedName}>& transform,
+               const ::bond::bonded<void, #{protocolReader}&>& value);|]
 
-    serialization transform Protocol {..} = [lt|
-    #{attr}bool Apply(const ::bond::#{transform}<#{protocolWriter} >& transform,
-               const #{qualifiedName}& value)#{body}
+    serialization (ProtocolReader _) _ = mempty
+    serialization (ProtocolWriter protocolWriter) transform = [lt|
+    #{extern}template #{attr}
+    bool Apply(const ::bond::#{transform}<#{protocolWriter} >& transform,
+               const #{qualifiedName}& value);
 
-    #{attr}bool Apply(const ::bond::#{transform}<#{protocolWriter} >& transform,
-               const ::bond::bonded< #{qualifiedName}>& value)#{body}
-    #{newlineSep 1 (transcoding transform) protocols}|]
+    #{extern}template #{attr}
+    bool Apply(const ::bond::#{transform}<#{protocolWriter} >& transform,
+               const ::bond::bonded< #{qualifiedName}>& value);
+    #{newlineSep 1 transcoding protocols}|]
       where
-        transcoding transform' Protocol {protocolReader = fromReader} = [lt|
-    #{attr}bool Apply(const ::bond::#{transform'}<#{protocolWriter} >& transform,
-               const ::bond::bonded< #{qualifiedName}, #{fromReader}&>& value)#{body}|]
+        transcoding (ProtocolWriter _) = mempty
+        transcoding (ProtocolReader protocolReader) = [lt|
+    #{extern}template #{attr}
+    bool Apply(const ::bond::#{transform}<#{protocolWriter} >& transform,
+               const ::bond::bonded< #{qualifiedName}, #{protocolReader}&>& value);|]
 
 applyOverloads _ _ _ _ _ = mempty
diff --git a/src/Language/Bond/Codegen/Cpp/Apply_cpp.hs b/src/Language/Bond/Codegen/Cpp/Apply_cpp.hs
--- a/src/Language/Bond/Codegen/Cpp/Apply_cpp.hs
+++ b/src/Language/Bond/Codegen/Cpp/Apply_cpp.hs
@@ -11,7 +11,6 @@
 import Language.Bond.Codegen.TypeMapping
 import Language.Bond.Codegen.Util
 import Language.Bond.Codegen.Cpp.ApplyOverloads
-import qualified Language.Bond.Codegen.Cpp.Util as CPP
 
 -- | Codegen template for generating /base_name/_apply.cpp containing
 -- definitions of the @Apply@ function overloads for the specified protocols.
@@ -21,15 +20,12 @@
 #include "#{file}_apply.h"
 #include "#{file}_reflection.h"
 
-#{CPP.openNamespace cpp}
-    #{newlineSepEnd 1 (applyOverloads protocols cpp attr body) declarations}
-#{CPP.closeNamespace cpp}
+namespace bond
+{
+    #{newlineSepEnd 1 (applyOverloads protocols cpp attr extern) declarations}
+} // namespace bond
 |])
   where
-    body = [lt|
-    {
-        return ::bond::Apply<>(transform, value);
-    }|]
-
-    attr = [lt||]
+    attr = ""
+    extern = ""
 
diff --git a/src/Language/Bond/Codegen/Cpp/Apply_h.hs b/src/Language/Bond/Codegen/Cpp/Apply_h.hs
--- a/src/Language/Bond/Codegen/Cpp/Apply_h.hs
+++ b/src/Language/Bond/Codegen/Cpp/Apply_h.hs
@@ -14,7 +14,6 @@
 import Language.Bond.Codegen.Util
 import Language.Bond.Codegen.TypeMapping
 import Language.Bond.Codegen.Cpp.ApplyOverloads
-import qualified Language.Bond.Codegen.Cpp.Util as CPP
 
 -- | Codegen template for generating /base_name/_apply.h containing declarations of
 -- <https://microsoft.github.io/bond/manual/bond_cpp.html#optimizing-build-time Apply>
@@ -22,7 +21,7 @@
 apply_h :: [Protocol]   -- ^ List of protocols for which @Apply@ overloads should be generated
         -> Maybe String -- ^ Optional attribute to decorate the @Apply@ function declarations
         -> MappingContext -> String -> [Import] -> [Declaration] -> (String, Text)
-apply_h protocols attribute cpp file imports declarations = ("_apply.h", [lt|
+apply_h protocols export_attribute cpp file imports declarations = ("_apply.h", [lt|
 #pragma once
 
 #include "#{file}_types.h"
@@ -30,15 +29,15 @@
 #include <bond/stream/output_buffer.h>
 #{newlineSep 0 includeImport imports}
 
-#{CPP.openNamespace cpp}
-    #{newlineSepEnd 1 (applyOverloads protocols cpp attr semi) declarations}
-#{CPP.closeNamespace cpp}
+namespace bond
+{
+    #{newlineSepEnd 1 (applyOverloads protocols cpp export_attr extern) declarations}
+} // namespace bond
 |])
   where
-    includeImport (Import path) = [lt|#include "#{dropExtension path}_apply.h"|]
+    includeImport (Import path) = [lt|#include "#{dropExtension (slashForward path)}_apply.h"|]
 
-    attr = optional (\a -> [lt|#{a}
-    |]) attribute
+    export_attr = optional (\a -> [lt|#{a}|]) export_attribute
 
-    semi = [lt|;|]
+    extern = "extern "
 
diff --git a/src/Language/Bond/Codegen/Cpp/Comm_h.hs b/src/Language/Bond/Codegen/Cpp/Comm_h.hs
deleted file mode 100644
--- a/src/Language/Bond/Codegen/Cpp/Comm_h.hs
+++ /dev/null
@@ -1,329 +0,0 @@
--- Copyright (c) Microsoft. All rights reserved.
--- Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-{-# LANGUAGE QuasiQuotes, OverloadedStrings, RecordWildCards #-}
-
-module Language.Bond.Codegen.Cpp.Comm_h (comm_h) where
-
-import System.FilePath
-import Data.Monoid
-import Prelude
-import qualified Data.Text.Lazy as L
-import Data.Text.Lazy.Builder
-import Text.Shakespeare.Text
-import Language.Bond.Syntax.Types
-import Language.Bond.Syntax.Util
-import Language.Bond.Codegen.Util
-import Language.Bond.Codegen.TypeMapping
-import qualified Language.Bond.Codegen.Cpp.Util as CPP
-
-
--- | Codegen template for generating /base_name/_comm.h containing declarations of
--- of service interface and proxy.
-comm_h :: MappingContext -> String -> [Import] -> [Declaration] -> (String, L.Text)
-comm_h cpp file imports declarations = ("_comm.h", [lt|
-#pragma once
-
-#include <bond/comm/services.h>
-#include "#{file}_types.h"
-#{newlineSep 0 includeImport imports}
-
-#{CPP.openNamespace cpp}
-    #{doubleLineSep 1 comm declarations}
-
-#{CPP.closeNamespace cpp}
-|])
-  where
-    includeImport (Import path) = [lt|#include "#{dropExtension path}_comm.h"|]
-
-    cppType = getTypeName cpp
-
-    request mt = request' (payload mt)
-      where
-        payload = maybe "void" cppType
-        request' params =  [lt|::bond::comm::payload<#{padLeft}#{params}>|]
-          where
-            paramsText = toLazyText params
-            padLeft = if L.head paramsText == ':' then [lt| |] else mempty
-
-    response mt = response' (payload mt)
-      where
-        payload = maybe "void" cppType
-        response' params =  [lt|::bond::comm::message<#{padLeft}#{params}>|]
-          where
-            paramsText = toLazyText params
-            padLeft = if L.head paramsText == ':' then [lt| |] else mempty
-
-    callback m = [lt|const std::function<void (const #{response m}&)>& callback|]
-
-    comm s@Service {..} = [lt|#{template}class #{declName}
-    {
-    public:
-        virtual ~#{declName}() = default;
-
-        #{doubleLineSep 2 virtualMethod serviceMethods}
-
-        struct Schema;
-        class Proxy;
-
-        template <template <typename> class Promise>
-        class Using;
-    };
-
-    #{template}struct #{className}::Schema
-    {
-        static const ::bond::Metadata metadata;
-
-        #{newlineSep 2 methodMetadata serviceMethods}
-
-        public: struct service
-        {
-            #{doubleLineSep 3 methodTemplate serviceMethods}
-        };
-
-        private: typedef boost::mpl::list<> methods0;
-        #{newlineSep 2 pushMethod indexedMethods}
-
-        public: typedef #{typename}methods#{length serviceMethods}::type methods;
-        #{constructor}
-    };
-    #{onlyTemplate $ CPP.schemaMetadata cpp s}
-
-    #{template}class #{className}::Proxy
-        : public #{className}
-    {
-    public:
-        template <typename ServiceProxy>
-        explicit
-        Proxy(const ServiceProxy& proxy,
-              const std::string& name = #{className}::Schema::metadata.qualified_name)
-            : _impl(boost::make_shared<__Impl<ServiceProxy>>(proxy, name))
-        {}
-
-        explicit
-        Proxy(const boost::shared_ptr<#{className}>& service)
-            : _impl(service)
-        {}
-
-        Proxy() = default;
-
-        #{doubleLineSep 2 proxyMethod serviceMethods}
-
-        template <template <typename> class Promise>
-        class Using;
-
-    protected:
-        boost::shared_ptr<#{className}> _impl;
-
-        template <typename ServiceProxy>
-        class __Impl
-            : public #{className}
-        {
-        public:
-            __Impl(const ServiceProxy& proxy, const std::string& name)
-                : _proxy(proxy),
-                  _name(name)
-            {}
-
-            virtual ~__Impl() = default;
-
-            #{doubleLineSep 3 implMethod serviceMethods}
-
-        private:
-            ServiceProxy _proxy;
-            const std::string _name;
-        };
-    };
-
-    #{template}template <template <typename> class Promise>
-    class #{className}::Using
-        : public #{className}
-    {
-    public:
-        #{doubleLineSep 2 virtualFutureMethod serviceMethods}
-
-        #{doubleLineSep 2 serviceMethod serviceMethods}
-    };
-
-    #{template}template <template <typename> class Promise>
-    class #{className}::Proxy::Using
-        : public #{className}::Proxy
-    {
-    public:
-        template <typename ServiceProxy>
-        explicit
-        Using(const ServiceProxy& proxy,
-              const std::string& name = #{className}::Schema::metadata.qualified_name)
-            : #{className}::Proxy(proxy, name)
-        {}
-
-        explicit
-        Using(const boost::shared_ptr<#{className}>& service)
-            : #{className}::Proxy(service)
-        {}
-
-        Using() = default;
-
-        #{doubleLineSep 2 proxyFutureMethod serviceMethods}
-    };
-    |]
-      where
-        className = CPP.className s
-        template = CPP.template s
-        onlyTemplate x = if null declParams then mempty else x
-        typename = onlyTemplate [lt|typename |]
-
-        methodMetadataVar m = [lt|s_#{methodName m}_metadata|]
-
-        methodMetadata m =
-            [lt|private: static const ::bond::Metadata #{methodMetadataVar m};|]
-
-        -- reversed list of method names zipped with indexes
-        indexedMethods :: [(String, Int)]
-        indexedMethods = zipWith ((,) . methodName) (reverse serviceMethods) [0..]
-
-        pushMethod (method, i) =
-            [lt|private: typedef #{typename}boost::mpl::push_front<methods#{i}, #{typename}service::#{method}>::type methods#{i + 1};|]
-
-        -- constructor, generated only for service templates
-        constructor = onlyTemplate [lt|
-            Schema()
-            {
-                // Force instantiation of template statics
-                (void)metadata;
-                #{newlineSep 4 static serviceMethods}
-            }|]
-          where
-            static m = [lt|(void)#{methodMetadataVar m};|]
-
-        methodTemplate m = [lt|typedef ::bond::reflection::MethodTemplate<
-                #{className},
-                #{request $ methodInput m},
-                #{result m},
-                &#{className}::#{methodName m},
-                &#{methodMetadataVar m}
-            > #{methodName m};|]
-          where
-            result Event{} = "void"
-            result Function{..} = response methodResult
-
-        methodSignature n m =
-            [lt|void #{methodName m}(#{commaLineSep n id $ methodParams m})|]
-          where
-            methodParams Event{..} =
-                [ [lt|const #{request methodInput}& input|]
-                ]
-
-            methodParams Function{..} =
-                [ [lt|const #{request methodInput}& input|]
-                , callback methodResult
-                ]
-
-        resultOf x f = [lt|decltype(std::declval< #{x}>().#{f}())|]
-
-        promiseType result = [lt|Promise< #{response result}>|]
-
-        futureType result = resultOf (promiseType result) get_future
-          where
-            get_future = [lt|get_future|]
-
-        methodFutureSignature Function{..} =
-            [lt|auto #{methodName}(const #{request methodInput}& input)
-            -> #{futureType methodResult}|]
-        methodFutureSignature Event{..} = error "No future-based signature for Event methods"
-
-        virtualMethod m = [lt|virtual #{methodSignature 3 m} = 0;|]
-
-        virtualFutureMethod Event{} = mempty
-        virtualFutureMethod m = [lt|virtual #{methodFutureSignature m} = 0;|]
-
-        serviceMethod Event{} = mempty
-        serviceMethod m@Function{..} = [lt|#{methodSignature 3 m} override
-        {
-            when(#{methodName}(input), ::bond::comm::Continuation(callback));
-        }|]
-
-        proxyMethod m@Event{..} = [lt|#{methodSignature 3 m} override
-        {
-            _impl->#{methodName}(input);
-        }#{proxyMethodOverload methodInput}|]
-          where
-            proxyMethodOverload Nothing = [lt|
-
-        void #{methodName}()
-        {
-            _impl->#{methodName}(::bond::comm::payload<void>());
-        }|]
-            proxyMethodOverload (Just payload) | isStruct payload = [lt|
-
-        void #{methodName}(const #{cppType payload}& input)
-        {
-            _impl->#{methodName}(boost::cref(input));
-        }|]
-            proxyMethodOverload _ = mempty
-
-        proxyMethod m@Function{..} = [lt|#{methodSignature 3 m} override
-        {
-            _impl->#{methodName}(input, callback);
-        }#{proxyMethodOverload methodInput}|]
-          where
-            proxyMethodOverload Nothing = [lt|
-
-        void #{methodName}(
-            #{callback methodResult})
-        {
-            _impl->#{methodName}(::bond::comm::payload<void>(), callback);
-        }|]
-            proxyMethodOverload (Just payload) | isStruct payload = [lt|
-
-        void #{methodName}(const #{cppType payload}& input,
-            #{callback methodResult})
-        {
-            _impl->#{methodName}(boost::cref(input), callback);
-        }|]
-            proxyMethodOverload _ = mempty
-
-        proxyFutureMethod Event{} = mempty
-        proxyFutureMethod m@Function{..} = [lt|using #{className}::Proxy::#{methodName};
-
-        #{methodFutureSignature m}
-        {
-            auto promise = boost::make_shared<#{promiseType methodResult}>();
-
-            _impl->#{methodName}(input,
-                [=](const #{response methodResult}& result) mutable
-                {
-                    promise->set_value(result);
-                });
-
-            return promise->get_future();
-        }#{proxyMethodOverload methodInput}|]
-          where
-            proxyMethodOverload Nothing = [lt|
-
-        auto #{methodName}()
-            -> #{futureType methodResult}
-        {
-            return #{methodName}(::bond::comm::payload<void>());
-        }|]
-            proxyMethodOverload (Just payload) | isStruct payload = [lt|
-
-        auto #{methodName}(const #{cppType payload}& input)
-            -> #{futureType methodResult}
-        {
-            return #{methodName}(#{request methodInput}(boost::cref(input)));
-        }
-        |]
-            proxyMethodOverload _ = mempty
-
-        implMethod m@Event{..} = [lt|#{methodSignature 4 m} override
-            {
-                _proxy.Send(_name, Schema::service::#{methodName}::metadata.name, input);
-            }|]
-
-        implMethod m@Function{..} = [lt|#{methodSignature 4 m} override
-            {
-                _proxy.Send(_name, Schema::service::#{methodName}::metadata.name, input, callback);
-            }|]
-
-    comm _ = mempty
diff --git a/src/Language/Bond/Codegen/Cpp/Enum_h.hs b/src/Language/Bond/Codegen/Cpp/Enum_h.hs
--- a/src/Language/Bond/Codegen/Cpp/Enum_h.hs
+++ b/src/Language/Bond/Codegen/Cpp/Enum_h.hs
@@ -20,6 +20,8 @@
 enum_h cpp _file _imports declarations = ("_enum.h", [lt|
 #pragma once
 
+#include <stdint.h>
+
 #{CPP.openNamespace cpp}
 namespace _bond_enumerators
 {
diff --git a/src/Language/Bond/Codegen/Cpp/Reflection_h.hs b/src/Language/Bond/Codegen/Cpp/Reflection_h.hs
--- a/src/Language/Bond/Codegen/Cpp/Reflection_h.hs
+++ b/src/Language/Bond/Codegen/Cpp/Reflection_h.hs
@@ -11,6 +11,7 @@
 import Data.Text.Lazy (Text)
 import qualified Data.Foldable as F
 import Text.Shakespeare.Text
+import Language.Bond.Util
 import Language.Bond.Syntax.Types
 import Language.Bond.Codegen.TypeMapping
 import Language.Bond.Codegen.Util
@@ -18,8 +19,8 @@
 
 -- | Codegen template for generating /base_name/_reflection.h containing schema
 -- metadata definitions.
-reflection_h :: MappingContext -> String -> [Import] -> [Declaration] -> (String, Text)
-reflection_h cpp file imports declarations = ("_reflection.h", [lt|
+reflection_h :: Maybe String -> MappingContext -> String -> [Import] -> [Declaration] -> (String, Text)
+reflection_h export_attribute cpp file imports declarations = ("_reflection.h", [lt|
 #pragma once
 
 #include "#{file}_types.h"
@@ -30,13 +31,13 @@
 #{CPP.closeNamespace cpp}
 |])
   where
-    idl = MappingContext idlTypeMapping [] [] []  
+    idl = MappingContext idlTypeMapping [] [] []
 
     -- C++ type
     cppType = getTypeName cpp
 
     -- template for generating #include statement from import
-    include (Import path) = [lt|#include "#{dropExtension path}_reflection.h"|]
+    include (Import path) = [lt|#include "#{dropExtension (slashForward path)}_reflection.h"|]
 
     -- template for generating struct schema
     schema s@Struct {..} = [lt|//
@@ -46,11 +47,11 @@
     {
         typedef #{baseType structBase} base;
 
-        static const ::bond::Metadata metadata;
+        #{export_attr}static const ::bond::Metadata metadata;
         #{newlineBeginSep 2 fieldMetadata structFields}
 
         public: struct var
-        {#{fieldTemplates structFields}};
+        {#{fieldTemplates (zip structFields uniqueFieldTemplateStructNames)}};
 
         private: typedef boost::mpl::list<> fields0;
         #{newlineSep 2 pushField indexedFields}
@@ -71,7 +72,11 @@
 
         className = CPP.className s
 
+        export_attr = onlyNonTemplate $ optional (\a -> [lt|#{a}
+        |]) export_attribute
+
         onlyTemplate x = if null declParams then mempty else x
+        onlyNonTemplate x = if null declParams then x else mempty
 
         metadataInitArgs = onlyTemplate [lt|<boost::mpl::list#{classParams} >|]
 
@@ -87,7 +92,7 @@
         }|]
           where
             static Field {..} = [lt|(void)s_#{fieldName}_metadata;|]
-        
+
         -- reversed list of field names zipped with indexes
         indexedFields :: [(String, Int)]
         indexedFields = zipWith ((,) . fieldName) (reverse structFields) [0..]
@@ -99,18 +104,27 @@
             [lt|private: typedef #{typename}boost::mpl::push_front<fields#{i}, #{typename}var::#{field}>::type fields#{i + 1};|]
 
         fieldMetadata Field {..} =
-            [lt|private: static const ::bond::Metadata s_#{fieldName}_metadata;|]
+            [lt|private: #{export_attr}static const ::bond::Metadata s_#{fieldName}_metadata;|]
 
-        fieldTemplates = F.foldMap $ \ f@Field {..} -> [lt|
+        -- fieldTemplateReservedNames are names used in ::bond::reflection::FieldTemplate<>
+        fieldTemplateReservedNames = ["FieldTemplate", "struct_type", "field_pointer", "field_type", "value_type", "field_modifier", "metadata", "field", "id", "GetVariable"]
+
+        fieldNames = map (\f -> fieldName f) structFields
+
+        fieldTemplateStructReservedNames = fieldTemplateReservedNames ++ fieldNames
+
+        uniqueFieldTemplateStructNames = uniqueNames (map (\n -> n ++ "_type") fieldNames) fieldTemplateStructReservedNames
+
+        fieldTemplates = F.foldMap $ \ (f@Field {..}, sn) -> [lt|
             // #{fieldName}
-            typedef ::bond::reflection::FieldTemplate<
+            typedef struct #{sn} : ::bond::reflection::FieldTemplate<
                 #{fieldOrdinal},
                 #{CPP.modifierTag f},
                 #{className},
                 #{cppType fieldType},
                 &#{className}::#{fieldName},
                 &s_#{fieldName}_metadata
-            > #{fieldName};
+            > {} #{fieldName};
         |]
 
 
diff --git a/src/Language/Bond/Codegen/Cpp/Types_Comm_cpp.hs b/src/Language/Bond/Codegen/Cpp/Types_Comm_cpp.hs
deleted file mode 100644
--- a/src/Language/Bond/Codegen/Cpp/Types_Comm_cpp.hs
+++ /dev/null
@@ -1,34 +0,0 @@
--- Copyright (c) Microsoft. All rights reserved.
--- Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-{-# LANGUAGE QuasiQuotes, OverloadedStrings, RecordWildCards #-}
-
-module Language.Bond.Codegen.Cpp.Types_Comm_cpp (types_comm_cpp) where
-
-import Data.Monoid
-import Prelude
-import Data.Text.Lazy (Text)
-import Text.Shakespeare.Text
-import Language.Bond.Syntax.Types
-import Language.Bond.Codegen.TypeMapping
-import Language.Bond.Codegen.Util
-import qualified Language.Bond.Codegen.Cpp.Util as CPP
-
--- | Codegen template for generating /base_name/_comm_types.cpp containing
--- definitions of helper functions and schema metadata static variables.
-types_comm_cpp :: MappingContext -> String -> [Import] -> [Declaration] -> (String, Text)
-types_comm_cpp cpp file _imports declarations = ("_comm.cpp", [lt|
-#include "#{file}_reflection.h"
-#include "#{file}_comm.h"
-#include <bond/core/exception.h>
-
-#{CPP.openNamespace cpp}
-    #{doubleLineSepEnd 1 statics declarations}
-#{CPP.closeNamespace cpp}
-|])
-  where
-    -- definitions of Schema statics for non-generic services
-    statics s@Service {..} =
-        if null declParams then CPP.schemaMetadata cpp s else mempty
-
-    statics _ = mempty
diff --git a/src/Language/Bond/Codegen/Cpp/Types_cpp.hs b/src/Language/Bond/Codegen/Cpp/Types_cpp.hs
--- a/src/Language/Bond/Codegen/Cpp/Types_cpp.hs
+++ b/src/Language/Bond/Codegen/Cpp/Types_cpp.hs
@@ -20,12 +20,15 @@
 types_cpp cpp file _imports declarations = ("_types.cpp", [lt|
 #include "#{file}_reflection.h"
 #include <bond/core/exception.h>
-
+#{unorderedMapInclude}
 #{CPP.openNamespace cpp}
     #{doubleLineSepEnd 1 statics declarations}
 #{CPP.closeNamespace cpp}
 |])
   where
+    unorderedMapInclude = if not (any CPP.isEnumDeclaration declarations) then mempty else [lt|#include <unordered_map>
+|]
+
     -- definitions of Schema statics for non-generic structs
     statics s@Struct {..} =
         if null declParams then CPP.schemaMetadata cpp s else mempty
@@ -40,21 +43,22 @@
     {
     namespace #{declName}
     {
-        const
-        std::map<std::string, enum #{declName}> _name_to_value_#{declName} =
-            boost::assign::map_list_of<std::string, enum #{declName}>
-                #{newlineSep 4 constant enumConstants};
-
-        const
-        std::map<enum #{declName}, std::string> _value_to_name_#{declName} =
-            ::bond::reverse_map(_name_to_value_#{declName});
-
+        namespace
+        {
+            struct _hash_#{declName}
+            {
+                std::size_t operator()(enum #{declName} value) const
+                {
+                    return static_cast<std::size_t>(value);
+                }
+            };
+        }
         const std::string& ToString(enum #{declName} value)
         {
-            std::map<enum #{declName}, std::string>::const_iterator it =
-                GetValueToNameMap(value).find(value);
+            const auto& map = GetValueToNameMap<std::unordered_map<enum #{declName}, std::string, _hash_#{declName}> >(value);
+            auto it = map.find(value);
 
-            if (GetValueToNameMap(value).end() == it)
+            if (map.end() == it)
                 ::bond::InvalidEnumValueException(value, "#{declName}");
 
             return it->second;
@@ -65,9 +69,34 @@
             if (!ToEnum(value, name))
                 ::bond::InvalidEnumValueException(name.c_str(), "#{declName}");
         }
+
+        bool ToEnum(enum #{declName}& value, const std::string& name)
+        {
+            const auto& map = GetNameToValueMap<std::unordered_map<std::string, enum #{declName}> >(value);
+            auto it = map.find(name);
+
+            if (map.end() == it)
+                return false;
+
+            value = it->second;
+
+            return true;
+        }
+
+        bool FromEnum(std::string& name, enum #{declName} value)
+        {
+            const auto& map = GetValueToNameMap<std::unordered_map<enum #{declName}, std::string, _hash_#{declName}> >(value);
+            auto it = map.find(value);
+
+            if (map.end() == it)
+                return false;
+
+            name = it->second;
+
+            return true;
+        }
+
     } // namespace #{declName}
     } // namespace _bond_enumerators|]
-      where
-        constant Constant {..} = [lt|("#{constantName}", #{constantName})|]
 
     statics _ = mempty
diff --git a/src/Language/Bond/Codegen/Cpp/Types_h.hs b/src/Language/Bond/Codegen/Cpp/Types_h.hs
--- a/src/Language/Bond/Codegen/Cpp/Types_h.hs
+++ b/src/Language/Bond/Codegen/Cpp/Types_h.hs
@@ -26,23 +26,25 @@
 
 -- | Codegen template for generating /base_name/_type.h containing definitions
 -- of C++ types representing the schema.
-types_h :: [String]     -- ^ list of optional header files to be @#include@'ed by the generated code
+types_h :: Maybe String -- ^ Optional attribute to decorate the enum conversion function declarations
+        -> [String]     -- ^ list of optional header files to be @#include@'ed by the generated code
         -> Bool         -- ^ 'True' to generate enum definitions into a separate file /base_name/_enum.h
         -> Maybe String -- ^ optional custom allocator to be used in the generated code
+        -> Bool         -- ^ 'True' to generate constructors with allocator
+        -> Bool         -- ^ 'True' to generate type aliases
+        -> Bool         -- ^ 'True' to use std::scoped_allocator_adaptor for strings and containers
         -> MappingContext -> String -> [Import] -> [Declaration] -> (String, L.Text)
-types_h userHeaders enumHeader allocator cpp file imports declarations = ("_types.h", [lt|
+types_h export_attribute userHeaders enumHeader allocator alloc_ctors_enabled type_aliases_enabled scoped_alloc_enabled cpp file imports declarations = ("_types.h", [lt|
 #pragma once
 #{newlineBeginSep 0 includeHeader userHeaders}
 #include <bond/core/bond_version.h>
 
-#if BOND_VERSION < 0x0422
-#error This file was generated by a newer version of Bond compiler
-#error and is incompatible with your version Bond library.
+#if BOND_VERSION < 0x0b00
+#error This file was generated by a newer version of the Bond compiler and is incompatible with your version of the Bond library.
 #endif
 
 #if BOND_MIN_CODEGEN_VERSION > 0x#{hexVersion version}
-#error This file was generated by an older version of Bond compiler
-#error and is incompatible with your version Bond library.
+#error This file was generated by an older version of the Bond compiler and is incompatible with your version of the Bond library.
 #endif
 
 #include <bond/core/config.h>
@@ -51,19 +53,26 @@
 #{includeEnum}
 #{newlineSepEnd 0 includeImport imports}
 #{CPP.openNamespace cpp}
-    #{doubleLineSep 1 typeDeclaration declarations}
+    #{doubleLineSepEnd 1 id $ catMaybes $ aliasDeclarations}#{doubleLineSep 1 typeDeclaration declarations}
 #{CPP.closeNamespace cpp}
-#{optional usesAllocatorSpecialization allocator}
 |])
   where
+    aliasDeclarations = if type_aliases_enabled then map aliasDeclName declarations else []
+
+    aliasDeclName a@Alias {..} = Just [lt|#{CPP.template a}using #{declName} = #{getAliasDeclTypeName cpp a};|]
+    aliasDeclName _ = Nothing
+
     hexVersion (Version xs _) = foldr showHex "" xs
     cppType = getTypeName cpp
 
+    cppExpandAliases = if type_aliases_enabled then cpp { typeMapping = cppExpandAliasesTypeMapping $ typeMapping cpp } else cpp
+    cppTypeExpandAliases = getTypeName cppExpandAliases
+
     idl = MappingContext idlTypeMapping [] [] []
 
     cppDefaultValue = CPP.defaultValue cpp
 
-    includeImport (Import path) = [lt|#include "#{dropExtension path}_types.h"|]
+    includeImport (Import path) = [lt|#include "#{dropExtension (slashForward path)}_types.h"|]
 
     optionalHeader (False, _) = mempty
     optionalHeader (True, header) = includeHeader header
@@ -87,29 +96,14 @@
 
     anyNullable = Any . isNullable
 
+    anyStringOrContainer f = Any (isString f || isMetaName f || isContainer f)
+
     bondHeaders :: [(Bool, String)]
     bondHeaders = [
         (have anyNullable, "<bond/core/nullable.h>"),
         (have anyBonded, "<bond/core/bonded.h>"),
-        (have anyBlob, "<bond/core/blob.h>")]
-
-    usesAllocatorSpecialization alloc = [lt|
-#if !defined(BOND_NO_CXX11_ALLOCATOR)
-namespace std
-{
-    #{doubleLineSep 1 usesAllocator declarations}
-}
-#endif
-|]
-      where
-        usesAllocator s@Struct {..} = [lt|template <typename _Alloc#{sepBeginBy ", typename " paramName declParams}>
-    struct uses_allocator<#{typename} #{getDeclTypeName cpp s}#{CPP.classParams s}, _Alloc>
-        : is_convertible<_Alloc, #{allocParam}>
-    {};|]
-          where
-            typename = if null declParams then mempty else [lt|typename|]
-            allocParam = if last alloc == '>' then alloc ++ " " else alloc
-        usesAllocator _ = mempty
+        (have anyBlob, "<bond/core/blob.h>"),
+        (scoped_alloc_enabled && have anyStringOrContainer, "<scoped_allocator>")]
 
     -- forward declaration
     typeDeclaration f@Forward {..} = [lt|#{CPP.template f}struct #{declName};|]
@@ -118,10 +112,10 @@
     typeDeclaration s@Struct {..} = [lt|
     #{template}struct #{declName}#{optional base structBase}
     {
-        #{newlineSepEnd 2 field structFields}#{defaultCtor}
+        #{optional allocatorType allocator}#{newlineSepEnd 2 field structFields}#{defaultCtor}
 
-        #{copyCtor}
-        #{moveCtor}
+        #{copyCtor}#{ifThenElse alloc_ctors_enabled (optional allocatorCopyCtor allocator) mempty}
+        #{moveCtor}#{ifThenElse alloc_ctors_enabled (optional allocatorMoveCtor allocator) mempty}
         #{optional allocatorCtor allocator}
         #{assignmentOp}
 
@@ -130,9 +124,9 @@
             return true#{optional baseEqual structBase}#{newlineBeginSep 4 fieldEqual structFields};
         }
 
-        bool operator!=(const #{declName}& other) const
+        bool operator!=(const #{declName}& #{otherParamName}) const
         {
-            return !(*this == other);
+            return !(*this == #{otherParamName});
         }
 
         void swap(#{declName}&#{otherParam})
@@ -146,15 +140,19 @@
         #{initMetadata}
     };
 
-    #{template}inline void swap(#{qualifiedClassName}& left, #{qualifiedClassName}& right)
+    #{template}inline void swap(#{qualifiedClassName}& #{leftParamName}, #{qualifiedClassName}& #{rightParamName})
     {
-        left.swap(right);
+        #{leftParamName}.swap(#{rightParamName});
     }|]
       where
         template = CPP.template s
         qualifiedClassName = CPP.qualifiedClassName cpp s
 
-        otherParam = if hasOnlyMetaFields then mempty else [lt| other|]
+        fieldNames :: [String]
+        fieldNames = foldMapStructFields (return . fieldName) s
+
+        otherParamName = uniqueName "other" fieldNames
+        otherParam = if hasOnlyMetaFields then mempty else ' ':otherParamName
         hasOnlyMetaFields = not (any (not . getAny . metaField) structFields) && isNothing structBase
         hasMetaFields = getAny $ foldMapStructFields metaField s
 
@@ -204,23 +202,37 @@
         {
         }|]
 
+        needAlloc alloc = isJust structBase || any (allocParameterized alloc . fieldType) structFields
+
+        allocParameterized alloc (BT_Nullable t) = allocParameterized alloc t
+        allocParameterized alloc t = (isStruct t) || (L.isInfixOf (L.pack alloc) $ toLazyText $ cppTypeExpandAliases t)
+
         -- default constructor
         defaultCtor = [lt|
-        #{declName}()#{initList}#{ctorBody}|]
+        #{dummyTemplateTag}#{declName}()#{initList}#{ctorBody}|]
           where
+            needAllocParam = maybe False needAlloc allocator
+
+            dummyTemplateTag = if needAllocParam
+                then [lt|template <int = 0> // Workaround to avoid compilation if not used
+        |]
+                else mempty
+
             initList = initializeList mempty
                 $ commaLineSep 3 fieldInit structFields
             fieldInit Field {..} = optional (\x -> [lt|#{fieldName}(#{x})|])
                 $ initValue fieldType fieldDefault
 
+        allocatorType alloc = [lt|using allocator_type = #{alloc};
+
+        |]
+
         allocatorCtor alloc = [lt|
         explicit
         #{declName}(const #{alloc}&#{allocParam})#{initList}#{ctorBody}
         |]
           where
-            allocParam = if needAlloc then [lt| allocator|] else mempty
-              where
-                needAlloc = isJust structBase || any (allocParameterized . fieldType) structFields
+            allocParam = if needAlloc alloc then [lt| allocator|] else mempty
             initList = initializeList
                 (optional baseInit structBase)
                 (commaLineSep 3 fieldInit structFields)
@@ -228,58 +240,73 @@
             fieldInit Field {..} = optional (\x -> [lt|#{fieldName}(#{x})|])
                 $ allocInitValue fieldType fieldDefault
             allocInitValue t@(BT_UserDefined a@Alias {} args) d
-                | allocParameterized t = allocInitValue (resolveAlias a args) d
+                | allocParameterized alloc t = allocInitValue (resolveAlias a args) d
                 | otherwise = initValue t d
             allocInitValue (BT_Nullable t) _ = allocInitValue t Nothing
             allocInitValue (BT_Maybe t) _ = allocInitValue t Nothing
             allocInitValue t (Just d)
                 | isString t = Just [lt|#{cppDefaultValue t d}, allocator|]
             allocInitValue t Nothing
-                | isList t || isMetaName t || isString t || isStruct t = Just "allocator"
-                | isAssociative t = Just [lt|std::less<#{keyType t}>(), allocator|]
+                | isContainer t || isMetaName t || isString t || isStruct t = Just "allocator"
             allocInitValue t d = initValue t d
-            keyType (BT_Set key) = cppType key
-            keyType (BT_Map key _) = cppType key
-            keyType (BT_UserDefined a@Alias {} args) = keyType $ resolveAlias a args
-            keyType _ = error "allocatorCtor/keyType: impossible happened."
-            allocParameterized t = (isStruct t) || (L.isInfixOf (L.pack alloc) . toLazyText $ cppType t)
 
         -- copy constructor
         copyCtor = if hasMetaFields then define else implicitlyDeclared
           where
             -- default OK when there are no meta fields
-            implicitlyDeclared = CPP.ifndef CPP.defaultedFunctions [lt|
+            implicitlyDeclared = [lt|
         // Compiler generated copy ctor OK
-        #{declName}(const #{declName}& other) = default;|]
+        #{declName}(const #{declName}&) = default;|]
 
             -- define ctor to initialize meta fields
-            define = [lt|#{declName}(const #{declName}& other)#{initList}#{ctorBody}|]
+            define = [lt|#{declName}(const #{declName}& #{otherParamName})#{initList}#{ctorBody}|]
               where
                 initList = initializeList
                     (optional baseCopy structBase)
                     (commaLineSep 3 fieldCopy structFields)
-                baseCopy b = [lt|#{cppType b}(other)|]
-                fieldCopy Field {..} = [lt|#{fieldName}(other.#{fieldName}#{getAllocator fieldType})|]
+                baseCopy b = [lt|#{cppType b}(#{otherParamName})|]
+                fieldCopy Field {..} = [lt|#{fieldName}(#{otherParamName}.#{fieldName}#{getAllocator fieldType})|]
                 getAllocator BT_MetaName = [lt|.get_allocator()|]
                 getAllocator BT_MetaFullName =  [lt|.get_allocator()|]
                 getAllocator _ = mempty
 
+        -- copy/move constructor with allocator
+        allocatorCopyOrMoveCtor otherParamDecl otherParamValue alloc = [lt|
+
+        #{declName}(#{otherParamDecl declName}#{otherParam}, const #{alloc}&#{allocParam})#{initList}#{ctorBody}|]
+          where
+            allocParam = if needAlloc alloc then [lt| allocator|] else mempty
+
+            initList = initializeList
+                (optional baseInit structBase)
+                (commaLineSep 3 fieldInit structFields)
+            baseInit b = [lt|#{cppType b}(#{otherParamValue $ L.pack otherParamName}, allocator)|]
+
+            fieldRef fieldName = [lt|#{otherParamName}.#{fieldName}|]
+            fieldInit Field {..} = [lt|#{fieldName}(#{otherParamValue $ fieldRef fieldName}#{allocInitValueText fieldType})|]
+
+            allocInitValueText fieldType = optional (\x -> [lt|, #{x}|])
+                $ allocInitValue fieldType
+            allocInitValue t@(BT_UserDefined a@Alias {} args)
+                | allocParameterized alloc t = allocInitValue (resolveAlias a args)
+                | otherwise = Nothing
+            allocInitValue (BT_Nullable t) = allocInitValue t
+            allocInitValue (BT_Maybe t) = allocInitValue t
+            allocInitValue t
+                | isList t || isMetaName t || isString t || isStruct t || isAssociative t = Just [lt|allocator|]
+                | otherwise = Nothing
+
+        -- copy constructor with allocator
+        allocatorCopyCtor alloc = allocatorCopyOrMoveCtor (\f -> [lt|const #{f}&|]) id alloc
+
         -- move constructor
         moveCtor = if hasMetaFields then [lt|
-#if !defined(#{CPP.rvalueReferences})
-        #{explicit}
-#endif|]
-            -- even if implicit would be okay, fall back to explicit for
-            -- compilers that don't support = default for move constructors
+        #{explicit}|]
                                     else [lt|
-#if !defined(#{CPP.defaultedMoveCtors})
-        #{implicit}
-#elif !defined(#{CPP.rvalueReferences})
-        #{explicit}
-#endif|]
+        #{implicit}|]
           where
             -- default OK when there are no meta fields
-            implicit = [lt|#{declName}(#{declName}&& other) = default;|]
+            implicit = [lt|#{declName}(#{declName}&&) = default;|]
 
             -- define ctor to perform member-by-member move and--if
             -- needed--initialize meta fields
@@ -287,22 +314,26 @@
             initList = initializeList
                 (optional baseMove structBase)
                 (commaLineSep 3 fieldMove structFields)
-            baseMove b = [lt|#{cppType b}(std::move(other))|]
-            fieldMove Field {..} = [lt|#{fieldName}(std::move(other.#{fieldName}))|]
-            param = if initList == mempty then mempty else [lt| other|]
+            baseMove b = [lt|#{cppType b}(std::move(#{otherParamName}))|]
+            fieldMove Field {..} = [lt|#{fieldName}(std::move(#{otherParamName}.#{fieldName}))|]
+            param = if initList == mempty then mempty else ' ':otherParamName
 
+        -- move constructor with allocator
+        allocatorMoveCtor alloc = (allocatorCopyOrMoveCtor (\f -> [lt|#{f}&&|]) (\f -> [lt|std::move(#{f})|]) alloc)
+
         -- operator=
         assignmentOp = if hasMetaFields then define else implicitlyDeclared
           where
             -- default OK when there are no meta fields
-            implicitlyDeclared = CPP.ifndef CPP.defaultedFunctions [lt|
+            implicitlyDeclared = [lt|
         // Compiler generated operator= OK
-        #{declName}& operator=(const #{declName}& other) = default;|]
+        #{declName}& operator=(const #{declName}&) = default;
+        #{declName}& operator=(#{declName}&&) = default;|]
 
             -- define operator= using swap
-            define = [lt|#{declName}& operator=(const #{declName}& other)
+            define = [lt|#{declName}& operator=(#{declName} #{otherParamName})
         {
-            #{declName}(other).swap(*this);
+            #{otherParamName}.swap(*this);
             return *this;
         }|]
 
@@ -310,18 +341,21 @@
         {#{newlineBeginSep 3 id [baseInit, nameInit, qualifiedInit]}
         }|]
           where
-            nameParam = if baseInit == mempty && nameInit == mempty then mempty else [lt| name|]
-            qualifiedNameParam = if baseInit == mempty && qualifiedInit == mempty then mempty else [lt| qualified_name|]
-            baseInit = optional (\b -> [lt|#{cppType b}::InitMetadata(name, qualified_name);|]) structBase
+            nameParam = if baseInit == mempty && nameInit == mempty then mempty else uniqueName "name" fieldNames
+            qualifiedNameParam = if baseInit == mempty && qualifiedInit == mempty then mempty else uniqueName "qual_name" fieldNames
+            baseInit = optional (\b -> [lt|#{cppType b}::InitMetadata(#{nameParam}, #{qualifiedNameParam});|]) structBase
             nameInit = newlineSep 3 init' structFields
               where
-                init' Field {fieldType = BT_MetaName, ..} = [lt|this->#{fieldName} = name;|]
+                init' Field {fieldType = BT_MetaName, ..} = [lt|this->#{fieldName} = #{nameParam};|]
                 init' _ = mempty
             qualifiedInit = newlineSep 3 init' structFields
               where
-                init' Field {fieldType = BT_MetaFullName, ..} = [lt|this->#{fieldName} = qualified_name;|]
+                init' Field {fieldType = BT_MetaFullName, ..} = [lt|this->#{fieldName} = #{qualifiedNameParam};|]
                 init' _ = mempty
 
+        leftParamName = uniqueName "left" fieldNames
+        rightParamName = uniqueName "right" fieldNames
+
     -- enum definition and helpers
     typeDeclaration e@Enum {..} = [lt|
     namespace _bond_enumerators
@@ -329,64 +363,44 @@
     namespace #{declName}
     {
         #{enumDefinition}
-        extern const std::map<enum #{declName}, std::string> _value_to_name_#{declName};
-        extern const std::map<std::string, enum #{declName}> _name_to_value_#{declName};
-
-        inline
-        const char* GetTypeName(enum #{declName})
+        inline BOND_CONSTEXPR const char* GetTypeName(enum #{declName})
         {
             return "#{declName}";
         }
 
-        inline
-        const char* GetTypeName(enum #{declName}, const ::bond::qualified_name_tag&)
+        inline BOND_CONSTEXPR const char* GetTypeName(enum #{declName}, const ::bond::qualified_name_tag&)
         {
             return "#{getDeclTypeName idl e}";
         }
 
-        inline
-        const std::map<enum #{declName}, std::string>& GetValueToNameMap(enum #{declName})
-        {
-            return _value_to_name_#{declName};
-        }
 
-        inline
-        const std::map<std::string, enum #{declName}>& GetNameToValueMap(enum #{declName})
+        template <typename Map = std::map<enum #{declName}, std::string> >
+        inline const Map& GetValueToNameMap(enum #{declName}, ::bond::detail::mpl::identity<Map> = {})
         {
-            return _name_to_value_#{declName};
+            static const Map s_valueToNameMap
+                {
+                    #{CPP.enumValueToNameInitList 5 e}
+                };
+            return s_valueToNameMap;
         }
 
-        const std::string& ToString(enum #{declName} value);
-
-        void FromString(const std::string& name, enum #{declName}& value);
-
-        inline
-        bool ToEnum(enum #{declName}& value, const std::string& name)
+        template <typename Map = std::map<std::string, enum #{declName}> >
+        inline const Map& GetNameToValueMap(enum #{declName}, ::bond::detail::mpl::identity<Map> = {})
         {
-            std::map<std::string, enum #{declName}>::const_iterator it =
-                _name_to_value_#{declName}.find(name);
-
-            if (_name_to_value_#{declName}.end() == it)
-                return false;
-
-            value = it->second;
-
-            return true;
+            static const Map s_nameToValueMap
+                {
+                    #{CPP.enumNameToValueInitList 5 e}
+                };
+            return s_nameToValueMap;
         }
+        #{export_attr}const std::string& ToString(enum #{declName} value);
 
-        inline
-        bool FromEnum(std::string& name, enum #{declName} value)
-        {
-            std::map<enum #{declName}, std::string>::const_iterator it =
-                _value_to_name_#{declName}.find(value);
+        #{export_attr}void FromString(const std::string& name, enum #{declName}& value);
 
-            if (_value_to_name_#{declName}.end() == it)
-                return false;
+        #{export_attr}bool ToEnum(enum #{declName}& value, const std::string& name);
 
-            name = it->second;
+        #{export_attr}bool FromEnum(std::string& name, enum #{declName} value);
 
-            return true;
-        }
     } // namespace #{declName}
     } // namespace _bond_enumerators
 
@@ -396,5 +410,6 @@
         |]
         enumUsing = if enumHeader then mempty else [lt|using namespace _bond_enumerators::#{declName};
     |]
+        export_attr = optional (\a -> [lt|#{a} |]) export_attribute
 
     typeDeclaration _ = mempty
diff --git a/src/Language/Bond/Codegen/Cpp/Util.hs b/src/Language/Bond/Codegen/Cpp/Util.hs
--- a/src/Language/Bond/Codegen/Cpp/Util.hs
+++ b/src/Language/Bond/Codegen/Cpp/Util.hs
@@ -15,13 +15,14 @@
     , defaultValue
     , attributeInit
     , schemaMetadata
-    , ifndef
-    , defaultedFunctions
-    , defaultedMoveCtors
-    , rvalueReferences
     , enumDefinition
+    , isEnumDeclaration
+    , enumValueToNameInitList
+    , enumNameToValueInitList
     ) where
 
+import Data.Int (Int64)
+import Data.List (sortOn)
 import Data.Monoid
 import Prelude
 import Data.Text.Lazy (Text, unpack)
@@ -67,10 +68,14 @@
 -- attribute initializer
 attributeInit :: [Attribute] -> Text
 attributeInit [] = "::bond::reflection::Attributes()"
-attributeInit xs = [lt|boost::assign::map_list_of<std::string, std::string>#{newlineBeginSep 5 attrNameValue xs}|]
+attributeInit xs = [lt|{
+                    #{commaLineSep 5 attrNameValueText sortedAttributes}
+                }|]
   where
-    idl = MappingContext idlTypeMapping [] [] []  
-    attrNameValue Attribute {..} = [lt|("#{getQualifiedName idl attrName}", "#{attrValue}")|]
+    idl = MappingContext idlTypeMapping [] [] []
+    attrNameValue Attribute {..} = (getQualifiedName idl attrName, attrValue)
+    sortedAttributes = sortOn fst $ map attrNameValue xs
+    attrNameValueText (name, value) = [lt|{ "#{name}", "#{value}" }|]
 
 
 -- modifier tag type for a field
@@ -103,6 +108,7 @@
 enumValue :: ToText a => MappingContext -> Type -> a -> Text
 enumValue cpp (BT_UserDefined e@Enum {..} _) x =
     [lt|#{getQualifiedName cpp $ getDeclNamespace cpp e}::_bond_enumerators::#{declName}::#{x}|]
+enumValue cpp (BT_UserDefined a@Alias {..} args) e = enumValue cpp (resolveAlias a args) e
 enumValue _ _ _ = error "enumValue: impossible happened."
 
 -- schema metadata static member definitions
@@ -146,16 +152,6 @@
                 #{attributeInit a});|]
 schemaMetadata _ _ = error "schemaMetadata: impossible happened."
 
-defaultedFunctions, defaultedMoveCtors, rvalueReferences :: Text
-defaultedFunctions = [lt|BOND_NO_CXX11_DEFAULTED_FUNCTIONS|]
-defaultedMoveCtors = [lt|BOND_NO_CXX11_DEFAULTED_MOVE_CTOR|]
-rvalueReferences = [lt|BOND_NO_CXX11_RVALUE_REFERENCES|]
-
-ifndef :: ToText a => a -> Text -> Text
-ifndef m = between [lt|
-#ifndef #{m}|] [lt|
-#endif|]
-
 enumDefinition :: Declaration -> Text
 enumDefinition Enum {..} = [lt|enum #{declName}
         {
@@ -166,3 +162,22 @@
     value (-2147483648) = [lt| = static_cast<int32_t>(-2147483647-1)|]
     value x = [lt| = static_cast<int32_t>(#{x})|]
 enumDefinition _ = error "enumDefinition: impossible happened."
+
+isEnumDeclaration :: Declaration -> Bool
+isEnumDeclaration Enum {} = True
+isEnumDeclaration _ = False
+
+
+enumValueToNameInitList :: Int64 -> Declaration -> Text
+enumValueToNameInitList n Enum {..} = commaLineSep n valueNameConst enumConstByValue
+  where
+    valueNameConst (name, _) = [lt|{ #{name}, "#{name}" }|]
+    enumConstByValue = sortOn snd $ reifyEnumValues enumConstants
+enumValueToNameInitList _ _ = error "enumValueToNameInitList: impossible happened."
+
+enumNameToValueInitList :: Int64 -> Declaration -> Text
+enumNameToValueInitList n Enum {..} = commaLineSep n nameValueConst enumConstByName
+  where
+    nameValueConst Constant {..} = [lt|{ "#{constantName}", #{constantName} }|]
+    enumConstByName = sortOn constantName enumConstants
+enumNameToValueInitList _ _ = error "enumNameToValueInitList: impossible happened."
diff --git a/src/Language/Bond/Codegen/Cs/Comm_cs.hs b/src/Language/Bond/Codegen/Cs/Comm_cs.hs
deleted file mode 100644
--- a/src/Language/Bond/Codegen/Cs/Comm_cs.hs
+++ /dev/null
@@ -1,203 +0,0 @@
--- Copyright (c) Microsoft. All rights reserved.
--- Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-{-# LANGUAGE QuasiQuotes, OverloadedStrings, RecordWildCards #-}
-
-module Language.Bond.Codegen.Cs.Comm_cs (
-  comm_interface_cs,
-  comm_proxy_cs,
-  comm_service_cs)
-where
-
-import Data.Maybe
-import Data.Monoid
-import Data.List (nub)
-import Prelude
-import qualified Data.Text.Lazy as L
-import Data.Text.Lazy.Builder
-import Text.Shakespeare.Text
-import Language.Bond.Syntax.Types
-import Language.Bond.Util
-import Language.Bond.Codegen.Util
-import Language.Bond.Codegen.TypeMapping
-import qualified Language.Bond.Codegen.Cs.Util as CS
-
-
-getMessageTypeName :: MappingContext -> Maybe Type -> Builder
-getMessageTypeName ctx t = maybe "global::Bond.Void" (getTypeName ctx) t
-
-getMessageProxyInputParam :: MappingContext -> Maybe Type -> Builder
-getMessageProxyInputParam ctx t = maybe "" constructParam t
-  where
-    constructParam x = getTypeName ctx x `mappend` fromText " param"
-
-paramOrBondVoid :: Maybe Type -> String
-paramOrBondVoid t = if isNothing t then "new global::Bond.Void()" else "param"
-
--- | Codegen template for generating code containing declarations of
--- of services including interfaces, proxies and services files.
-
-comm_interface_cs :: MappingContext -> String -> [Import] -> [Declaration] -> (String, L.Text)
-comm_interface_cs cs _ _ declarations = ("_interfaces.cs", [lt|
-#{CS.disableCscWarnings}
-#{CS.disableReSharperWarnings}
-namespace #{csNamespace}
-{
-    #{doubleLineSep 1 comm declarations}
-} // #{csNamespace}
-|])
-  where
-    csNamespace = sepBy "." toText $ getNamespace cs
-
-    comm s@Service{..} = [lt|#{CS.typeAttributes cs s}interface I#{declName}#{generics}
-    {
-        #{doubleLineSep 2 methodDeclaration serviceMethods}
-    }
-    |]
-      where
-        generics = angles $ sepBy ", " paramName declParams
-
-        methodDeclaration Function{..} = [lt|global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<#{getMessageResultTypeName}>> #{methodName}Async(global::Bond.Comm.IMessage<#{getMessageInputTypeName}> param, global::System.Threading.CancellationToken ct);|]
-          where
-            getMessageResultTypeName = getMessageTypeName cs methodResult
-            getMessageInputTypeName = getMessageTypeName cs methodInput
-
-        methodDeclaration Event{..} = [lt|void #{methodName}Async(global::Bond.Comm.IMessage<#{getMessageInputTypeName}> param);|]
-          where
-            getMessageInputTypeName = getMessageTypeName cs methodInput
-
-    comm _ = mempty
-
-comm_proxy_cs :: MappingContext -> String -> [Import] -> [Declaration] -> (String, L.Text)
-comm_proxy_cs cs _ _ declarations = ("_proxies.cs", [lt|
-#{CS.disableCscWarnings}
-#{CS.disableReSharperWarnings}
-namespace #{csNamespace}
-{
-    #{doubleLineSep 1 comm declarations}
-} // #{csNamespace}
-|])
-  where
-    csNamespace = sepBy "." toText $ getNamespace cs
-    idl = MappingContext idlTypeMapping [] [] []  
-
-    comm s@Service{..} = [lt|#{CS.typeAttributes cs s}public class #{declName}Proxy<#{proxyGenerics}TConnection> : I#{declName}#{interfaceGenerics}#{connConstraint}
-    {
-        private readonly TConnection m_connection;
-
-        public #{declName}Proxy(TConnection connection)
-        {
-            m_connection = connection;
-        }
-
-        #{doubleLineSep 2 proxyMethod serviceMethods}
-    }|]
-      where
-        methodCapability Function {} = "global::Bond.Comm.IRequestResponseConnection"
-        methodCapability Event {} = "global::Bond.Comm.IEventConnection"
-
-        getCapabilities :: [Method] -> [String]
-        getCapabilities m = nub $ map methodCapability m 
-        connConstraint = " where TConnection : " ++ sepBy ", " (\p -> p) (getCapabilities serviceMethods)
-
-        interfaceGenerics = angles $ sepBy "," paramName declParams -- of the form "<T1, T2, T3>"
-        proxyGenerics = sepEndBy ", " paramName declParams -- of the form "T1, T2, T3, "
-
-        proxyMethod Function{..} = [lt|public global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<#{getMessageResultTypeName}>> #{methodName}Async(#{getMessageProxyInputParam cs methodInput})
-        {
-            var message = new global::Bond.Comm.Message<#{getMessageInputTypeName}>(#{paramOrBondVoid methodInput});
-            return #{methodName}Async(message, global::System.Threading.CancellationToken.None);
-        }
-
-        public global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<#{getMessageResultTypeName}>> #{methodName}Async(global::Bond.Comm.IMessage<#{getMessageInputTypeName}> param, global::System.Threading.CancellationToken ct)
-        {
-            return m_connection.RequestResponseAsync<#{getMessageInputTypeName}, #{getMessageResultTypeName}>(
-                "#{getDeclTypeName idl s}",
-                "#{methodName}",
-                param,
-                ct);
-        }|]
-          where
-            getMessageResultTypeName = getMessageTypeName cs methodResult
-            getMessageInputTypeName = getMessageTypeName cs methodInput
-
-        proxyMethod Event{..} = [lt|public void #{methodName}Async(#{getMessageProxyInputParam cs methodInput})
-        {
-            var message = new global::Bond.Comm.Message<#{getMessageInputTypeName}>(#{paramOrBondVoid methodInput});
-            #{methodName}Async(message);
-        }
-
-        public void #{methodName}Async(global::Bond.Comm.IMessage<#{getMessageInputTypeName}> param)
-        {
-            m_connection.FireEventAsync<#{getMessageInputTypeName}>(
-                "#{getDeclTypeName idl s}",
-                "#{methodName}",
-                param);
-        }|]
-          where
-            getMessageInputTypeName = getMessageTypeName cs methodInput
-
-    comm _ = mempty
-
-comm_service_cs :: MappingContext -> String -> [Import] -> [Declaration] -> (String, L.Text)
-comm_service_cs cs _ _ declarations = ("_services.cs", [lt|
-#{CS.disableCscWarnings}
-#{CS.disableReSharperWarnings}
-namespace #{csNamespace}
-{
-    #{doubleLineSep 1 comm declarations}
-} // #{csNamespace}
-|])
-  where
-    csNamespace = sepBy "." toText $ getNamespace cs
-    idl = MappingContext idlTypeMapping [] [] []  
-
-    comm s@Service{..} = [lt|#{CS.typeAttributes cs s}public abstract class #{declName}ServiceBase#{generics} : I#{declName}#{generics}, global::Bond.Comm.IService
-    {
-        public global::System.Collections.Generic.IEnumerable<global::Bond.Comm.ServiceMethodInfo> Methods
-        {
-            get
-            {
-                #{newlineSep 4 methodInfo serviceMethods}
-            }
-        }
-
-        #{doubleLineSep 2 methodAbstract serviceMethods}
-
-        #{doubleLineSep 2 methodGlue serviceMethods}
-    }
-    |]
-      where
-        generics = angles $ sepBy ", " paramName declParams
-
-        methodInfo Function{..} = [lt|yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="#{getDeclTypeName idl s}.#{methodName}", Callback = #{methodName}Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};|]
-        methodInfo Event{..} = [lt|yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="#{getDeclTypeName idl s}.#{methodName}", Callback = #{methodName}Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.Event};|]
-
-        methodAbstract Function{..} = [lt|public abstract global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<#{getMessageResultTypeName}>> #{methodName}Async(global::Bond.Comm.IMessage<#{getMessageInputTypeName}> param, global::System.Threading.CancellationToken ct);|]
-          where
-            getMessageResultTypeName = getMessageTypeName cs methodResult
-            getMessageInputTypeName = getMessageTypeName cs methodInput
-
-        methodAbstract Event{..} = [lt|public abstract void #{methodName}Async(global::Bond.Comm.IMessage<#{getMessageInputTypeName}> param);|]
-          where
-            getMessageInputTypeName = getMessageTypeName cs methodInput
-
-        methodGlue Function{..} = [lt|private global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage> #{methodName}Async_Glue(global::Bond.Comm.IMessage param, global::Bond.Comm.ReceiveContext context, global::System.Threading.CancellationToken ct)
-        {
-            return global::Bond.Comm.CodegenHelpers.Upcast<global::Bond.Comm.IMessage<#{getMessageResultTypeName}>,
-                                                           global::Bond.Comm.IMessage>(
-                #{methodName}Async(param.Convert<#{getMessageInputTypeName}>(), ct));
-        }|]
-          where
-            getMessageResultTypeName = getMessageTypeName cs methodResult
-            getMessageInputTypeName = getMessageTypeName cs methodInput
-
-        methodGlue Event{..} = [lt|private global::System.Threading.Tasks.Task #{methodName}Async_Glue(global::Bond.Comm.IMessage param, global::Bond.Comm.ReceiveContext context, global::System.Threading.CancellationToken ct)
-        {
-            #{methodName}Async(param.Convert<#{getMessageInputTypeName}>());
-            return global::Bond.Comm.CodegenHelpers.CompletedTask;
-        }|]
-          where
-            getMessageInputTypeName = getMessageTypeName cs methodInput
-
-    comm _ = mempty
diff --git a/src/Language/Bond/Codegen/Cs/Types_cs.hs b/src/Language/Bond/Codegen/Cs/Types_cs.hs
--- a/src/Language/Bond/Codegen/Cs/Types_cs.hs
+++ b/src/Language/Bond/Codegen/Cs/Types_cs.hs
@@ -7,12 +7,12 @@
     ( types_cs
     , FieldMapping(..)
     , StructMapping(..)
+    , ConstructorOptions(..)
     ) where
 
 import Data.Monoid
-import qualified Data.Foldable as F
 import Prelude
-import Data.Text.Lazy (Text)
+import Data.Text.Lazy (Text, pack)
 import Text.Shakespeare.Text
 import Language.Bond.Syntax.Types
 import Language.Bond.Syntax.Util
@@ -34,12 +34,19 @@
     ReadOnlyProperties      -- ^ auto-properties with private setter
     deriving Eq
 
+-- | Options for how constructors should be generated.
+data ConstructorOptions =
+    DefaultWithProtectedBase | -- ^ The original bond behavior.
+    ConstructorParameters      -- ^ Generate a constructor that takes all the fields as parameters.
+    deriving Eq
+
 -- | Codegen template for generating definitions of C# types representing the schema.
 types_cs
     :: StructMapping        -- ^ Specifies how to represent schema structs
     -> FieldMapping         -- ^ Specifies how to represent schema fields
+    -> ConstructorOptions   -- ^ Specifies the constructors that should be generated
     -> MappingContext -> String -> [Import] -> [Declaration] -> (String, Text)
-types_cs structMapping fieldMapping cs _ _ declarations = (fileSuffix, [lt|
+types_cs structMapping fieldMapping constructorOptions cs _ _ declarations = (fileSuffix, [lt|
 #{CS.disableCscWarnings}
 #{CS.disableReSharperWarnings}
 namespace #{csNamespace}
@@ -71,6 +78,9 @@
     propertyAttributes f = case structMapping of
         Class -> CS.propertyAttributes cs f
 
+    baseClass x = [lt|
+        : #{csType x}|]
+
     -- C# type definition for schema struct
     typeDefinition s@Struct {..} = [lt|#{typeAttributes s}#{struct}#{declName}#{params}#{maybe interface baseClass structBase}#{constraints}
     {
@@ -86,21 +96,16 @@
         -- constraints
         constraints = CS.paramConstraints declParams
 
-        -- base
-        callBaseCtor = getAny $ optional (foldMapFields metaField) structBase
-
-        baseClass x = [lt|
-        : #{csType x}|]
-
-        baseCtor = if not callBaseCtor then mempty else [lt|
-            : base(fullName, name)|]
-
         -- default value
         csDefault = CS.defaultValue cs
 
-        -- constructors
-        constructors = if noCtor then mempty else [lt|
+        metaFields = filter (isMetaName . fieldType) structFields
 
+        noMetaFields = null metaFields
+
+        -- constructor: DefaultWithProtectedBase option
+        defaultWithProtectedBaseConstructor = if noCtor then mempty else [lt|
+
         public #{declName}()
             : this("#{getDeclTypeName idl s}", "#{declName}")
         {}
@@ -111,7 +116,67 @@
         }|]
           where
             noCtor = not callBaseCtor && (fieldMapping == PublicFields && noMetaFields || null structFields)
-            noMetaFields = not $ getAny $ F.foldMap metaField structFields
+            callBaseCtor = getAny $ optional (foldMapFields metaField) structBase
+            baseCtor = if not callBaseCtor
+                then mempty
+                else [lt|
+            : base(fullName, name)|]
+
+        -- constructor: ConstructorParameters option
+        constructorWithParameters = if not noMetaFields
+            then error $ "bond_meta usage in Struct " ++ (show declName) ++ " Field " ++ (show $ fieldName $ head metaFields) ++ " is incompatible with --preview--constructor-parameters"
+            else if (null baseFieldList)
+                then if (null structFields) 
+                     then [lt|
+        #{defaultConstructor}|]
+                     else [lt|
+
+        public #{declName}(
+            #{commaLineSep 3 paramDecl fieldNameList})
+        {
+            #{newlineSep 3 paramBasedInitializer fieldNameList}
+        }
+
+        #{defaultConstructor}|]
+                else [lt|
+
+        public #{declName}(
+            // Base class parameters
+            #{commaLineSep 3 paramDecl (zip baseFieldList uniqueBaseFieldNames)}#{thisParamBlock}
+        ) : base(
+                #{commaLineSep 4 pack uniqueBaseFieldNames})
+        {
+            #{newlineSep 3 paramBasedInitializer (zip structFields uniqueThisFieldNames)}
+        }
+
+        #{defaultConstructor}|]
+
+        thisParamBlock = if null structFields
+            then mempty
+            else [lt|,
+
+            // This class parameters
+            #{commaLineSep 3 paramDecl (zip structFields uniqueThisFieldNames)}|]
+
+        defaultConstructor = [lt|public #{declName}()
+        {
+            #{newlineSep 3 initializer structFields}
+        }|]
+
+        baseFieldList = concat $ baseFields s
+
+        uniqueBaseFieldNames = uniqueNames (map fieldName baseFieldList) []
+        uniqueThisFieldNames = uniqueNames (map fieldName structFields) uniqueBaseFieldNames
+
+        paramDecl (f, n) = [lt|#{csType $ fieldType f} #{n}|]
+
+        paramBasedInitializer (f, n) = [lt|this.#{fieldName f} = #{n};|]
+
+        fieldNameList = map (\f -> (f, fieldName f)) structFields
+
+        constructors = case constructorOptions of
+            DefaultWithProtectedBase -> defaultWithProtectedBaseConstructor
+            ConstructorParameters -> constructorWithParameters
 
         -- property or field
         property f@Field {..} =
diff --git a/src/Language/Bond/Codegen/Cs/Util.hs b/src/Language/Bond/Codegen/Cs/Util.hs
--- a/src/Language/Bond/Codegen/Cs/Util.hs
+++ b/src/Language/Bond/Codegen/Cs/Util.hs
@@ -16,7 +16,8 @@
 import Data.Int (Int64)
 import Data.Monoid
 import Prelude
-import Data.Text.Lazy (Text)
+import Data.Text.Lazy (Text, isPrefixOf)
+import Data.Text.Lazy.Builder (toLazyText)
 import Text.Shakespeare.Text
 import Paths_bond (version)
 import Data.Version (showVersion)
@@ -75,7 +76,9 @@
  <> generatedCodeAttr
 
 -- C# service attributes
-typeAttributes _ Service {..} = generatedCodeAttr
+typeAttributes cs s@Service {..} =
+    optionalTypeAttributes cs s
+    <> generatedCodeAttr
 
 typeAttributes _ _ = error "typeAttributes: impossible happened."
 
@@ -84,7 +87,7 @@
     |]
 
 idl :: MappingContext
-idl = MappingContext idlTypeMapping [] [] []  
+idl = MappingContext idlTypeMapping [] [] []
 
 optionalTypeAttributes :: MappingContext -> Declaration -> Text
 optionalTypeAttributes cs decl =
@@ -98,7 +101,7 @@
 
 -- Attributes defined by the user in the schema
 schemaAttributes :: Int64 -> [Attribute] -> Text
-schemaAttributes indent = newlineSepEnd indent schemaAttribute
+schemaAttributes indent_ = newlineSepEnd indent_ schemaAttribute
   where
     schemaAttribute Attribute {..} =
         [lt|[global::Bond.Attribute("#{getQualifiedName idl attrName}", "#{attrValue}")]|]
@@ -110,15 +113,20 @@
     constraint (TypeParam _ Nothing) = mempty
     constraint (TypeParam name (Just Value)) = [lt|where #{name} : struct|]
 
+isImmutableCollection :: MappingContext -> Type -> Bool
+isImmutableCollection cs t = [lt|System.Collections.Immutable.Immutable|] `isPrefixOf` toLazyText (getInstanceTypeName cs t)
+
 -- Initial value for C# field/property or Nothing if C# implicit default is OK
 defaultValue :: MappingContext -> Field -> Maybe Text
 defaultValue cs Field {fieldDefault = Nothing, ..} = implicitDefault fieldType
   where
     newInstance t = Just [lt|new #{getInstanceTypeName cs t}()|]
+    staticEmptyField t = Just [lt|#{getInstanceTypeName cs t}.Empty|]
     implicitDefault (BT_Bonded t) = Just [lt|global::Bond.Bonded<#{getTypeName cs t}>.Empty|]
     implicitDefault t@(BT_TypeParam _) = Just [lt|global::Bond.GenericFactory.Create<#{getInstanceTypeName cs t}>()|]
     implicitDefault t@BT_Blob = newInstance t
     implicitDefault t@(BT_UserDefined a@Alias {..} args)
+        | isImmutableCollection cs t = staticEmptyField t
         | customAliasMapping cs a = newInstance t
         | otherwise = implicitDefault $ resolveAlias a args
     implicitDefault t
diff --git a/src/Language/Bond/Codegen/CustomMapping.hs b/src/Language/Bond/Codegen/CustomMapping.hs
--- a/src/Language/Bond/Codegen/CustomMapping.hs
+++ b/src/Language/Bond/Codegen/CustomMapping.hs
@@ -11,11 +11,13 @@
     , parseNamespaceMapping
     ) where
 
-import Data.Char
-import Control.Applicative
-import Prelude
-import Text.Parsec hiding (many, optional, (<|>))
+import Control.Applicative hiding (some)
+import Data.Void (Void)
 import Language.Bond.Syntax.Types
+import Prelude
+import Text.Megaparsec hiding (many, optional, (<|>))
+import Text.Megaparsec.Char
+import qualified Text.Megaparsec.Char.Lexer as L
 
 -- | Specification of a fragment of type alias mappings.
 data Fragment =
@@ -34,46 +36,65 @@
     , toNamespace :: QualifiedName      -- ^ namespace in the generated code
     }
 
-type Parser a = Parsec SourceName () a
+type Parser = Parsec Void String
 
-whitespace :: Parser String
-whitespace = many (char ' ') <?> "whitespace"
 identifier :: Parser String
-identifier = many1 (alphaNum <|> char '_') <?> "identifier"
+identifier = some (alphaNumChar <|> char '_') <?> "identifier"
+
 qualifiedName :: Parser [String]
 qualifiedName = sepBy1 identifier (char '.') <?> "qualified name"
+
+sc :: Parser ()
+sc = L.space space1 empty empty
+
 symbol :: String -> Parser String
-symbol s = whitespace *> string s <* whitespace
+symbol = L.symbol sc
+
 equal :: Parser String
 equal = symbol "="
+
+-- consume whitespace after every lexeme
+lexeme :: Parser a -> Parser a
+lexeme = L.lexeme sc
+
+decimal :: Parser Integer
+decimal = lexeme L.decimal
+
+hexadecimal :: Parser Integer
+hexadecimal = lexeme . try $ char '0' >> char' 'x' >> L.hexadecimal
+
+octal :: Parser Integer
+octal = lexeme . try $ char '0' >> char' 'o' >> L.octal
+
+natural :: Parser Integer
+natural = hexadecimal <|> octal <|> decimal
+
 integer :: Parser Integer
-integer = decimal <$> many1 digit <?> "decimal number"
-  where
-    decimal = foldl (\x d -> 10 * x + toInteger (digitToInt d)) 0
+integer = L.signed sc natural
 
--- | Parse a type alias mapping specification used in command-line arguments of 
+-- | Parse a type alias mapping specification used in command-line arguments of
 -- <https://microsoft.github.io/bond/manual/compiler.html#command-line-options gbc>.
 --
 -- ==== __Examples__
 --
 -- > > parseAliasMapping "Example.OrderedSet=SortedSet<{0}>"
 -- > Right (AliasMapping {aliasName = ["Example","OrderedSet"], aliasTemplate = [Fragment "SortedSet<",Placeholder 0,Fragment ">"]})
-parseAliasMapping :: String -> Either ParseError AliasMapping 
-parseAliasMapping s = parse aliasMapping s s
+parseAliasMapping :: String -> Either (ParseErrorBundle String Void) AliasMapping
+parseAliasMapping s = parse aliasMapping "" s
   where
-    aliasMapping = AliasMapping <$> qualifiedName <* equal <*> many1 (placeholder <|> fragment) <* eof
+    aliasMapping = AliasMapping <$> qualifiedName <* equal <*> some (placeholder <|> fragment) <* eof
     placeholder = Placeholder <$> fromIntegral <$> between (char '{') (char '}') integer
-    fragment = Fragment <$> many1 (noneOf "{")
+    fragment = Fragment <$> some (anySingleBut '{')
 
--- | Parse a namespace mapping specification used in command-line arguments of 
+-- | Parse a namespace mapping specification used in command-line arguments of
 -- <https://microsoft.github.io/bond/manual/compiler.html#command-line-options gbc>.
 --
 -- ==== __Examples__
 --
 -- > > parseNamespaceMapping "bond=Microsoft.Bond"
 -- > Right (NamespaceMapping {fromNamespace = ["bond"], toNamespace = ["Microsoft","Bond"]})
-parseNamespaceMapping :: String -> Either ParseError NamespaceMapping
-parseNamespaceMapping s = parse namespaceMapping s s
+parseNamespaceMapping :: String -> Either (ParseErrorBundle String Void) NamespaceMapping
+parseNamespaceMapping s = parse namespaceMapping "" s
   where
     namespaceMapping = NamespaceMapping <$> qualifiedName <* equal <*> qualifiedName
 
diff --git a/src/Language/Bond/Codegen/Java/Class_java.hs b/src/Language/Bond/Codegen/Java/Class_java.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/Bond/Codegen/Java/Class_java.hs
@@ -0,0 +1,638 @@
+-- Copyright (c) Microsoft. All rights reserved.
+-- Licensed under the MIT license. See LICENSE file in the project root
+-- for full license information.
+
+{-# LANGUAGE QuasiQuotes, OverloadedStrings, RecordWildCards #-}
+
+module Language.Bond.Codegen.Java.Class_java
+    ( class_java
+    , JavaFieldMapping(..)
+    ) where
+
+import Prelude
+import Data.Text.Lazy (Text)
+import Text.Shakespeare.Text
+import Language.Bond.Syntax.Types
+import Language.Bond.Syntax.Util
+import Language.Bond.Util
+import Language.Bond.Codegen.TypeMapping
+import Language.Bond.Codegen.Util
+import Language.Bond.Codegen.Java.Util
+
+
+-- field -> public field
+data JavaFieldMapping = JavaPublicFields deriving Eq
+
+
+-- given the type of the field, returns the name of the struct field descriptor type (a protected nested class within StructBondType)
+structFieldDescriptorTypeName :: MappingContext -> Type -> Text
+structFieldDescriptorTypeName java = typeName
+    where
+        typeName (BT_Maybe BT_Int8) = [lt|org.bondlib.StructBondType.SomethingInt8StructField|]
+        typeName BT_Int8 = [lt|org.bondlib.StructBondType.Int8StructField|]
+        typeName (BT_Maybe BT_Int16) = [lt|org.bondlib.StructBondType.SomethingInt16StructField|]
+        typeName BT_Int16 = [lt|org.bondlib.StructBondType.Int16StructField|]
+        typeName (BT_Maybe BT_Int32) = [lt|org.bondlib.StructBondType.SomethingInt32StructField|]
+        typeName BT_Int32 = [lt|org.bondlib.StructBondType.Int32StructField|]
+        typeName (BT_Maybe BT_Int64) = [lt|org.bondlib.StructBondType.SomethingInt64StructField|]
+        typeName BT_Int64 = [lt|org.bondlib.StructBondType.Int64StructField|]
+        typeName (BT_Maybe BT_UInt8) = [lt|org.bondlib.StructBondType.SomethingUInt8StructField|]
+        typeName BT_UInt8 = [lt|org.bondlib.StructBondType.UInt8StructField|]
+        typeName (BT_Maybe BT_UInt16) = [lt|org.bondlib.StructBondType.SomethingUInt16StructField|]
+        typeName BT_UInt16 = [lt|org.bondlib.StructBondType.UInt16StructField|]
+        typeName (BT_Maybe BT_UInt32) = [lt|org.bondlib.StructBondType.SomethingUInt32StructField|]
+        typeName BT_UInt32 = [lt|org.bondlib.StructBondType.UInt32StructField|]
+        typeName (BT_Maybe BT_UInt64) = [lt|org.bondlib.StructBondType.SomethingUInt64StructField|]
+        typeName BT_UInt64 = [lt|org.bondlib.StructBondType.UInt64StructField|]
+        typeName (BT_Maybe BT_Float) = [lt|org.bondlib.StructBondType.SomethingFloatStructField|]
+        typeName BT_Float = [lt|org.bondlib.StructBondType.FloatStructField|]
+        typeName (BT_Maybe BT_Double) = [lt|org.bondlib.StructBondType.SomethingDoubleStructField|]
+        typeName BT_Double = [lt|org.bondlib.StructBondType.DoubleStructField|]
+        typeName (BT_Maybe BT_Bool) = [lt|org.bondlib.StructBondType.SomethingBoolStructField|]
+        typeName BT_Bool = [lt|org.bondlib.StructBondType.BoolStructField|]
+        typeName (BT_Maybe BT_String) = [lt|org.bondlib.StructBondType.SomethingStringStructField|]
+        typeName BT_String = [lt|org.bondlib.StructBondType.StringStructField|]
+        typeName (BT_Maybe BT_WString) = [lt|org.bondlib.StructBondType.SomethingWStringStructField|]
+        typeName BT_WString = [lt|org.bondlib.StructBondType.WStringStructField|]
+        typeName (BT_Maybe BT_MetaName) = [lt|org.bondlib.StructBondType.SomethingStringStructField|]
+        typeName BT_MetaName = [lt|org.bondlib.StructBondType.StringStructField|]
+        typeName (BT_Maybe BT_MetaFullName) = [lt|org.bondlib.StructBondType.SomethingStringStructField|]
+        typeName BT_MetaFullName = [lt|org.bondlib.StructBondType.StringStructField|]
+        typeName (BT_Maybe (BT_UserDefined e@Enum {} _)) = [lt|org.bondlib.StructBondType.SomethingEnumStructField<#{qualifiedDeclaredTypeName java e}>|]
+        typeName (BT_UserDefined e@Enum {} _) = [lt|org.bondlib.StructBondType.EnumStructField<#{qualifiedDeclaredTypeName java e}>|]
+        typeName (BT_Maybe (BT_UserDefined a@Alias {} args)) = structFieldDescriptorTypeName java (BT_Maybe (resolveAlias a args))
+        typeName (BT_UserDefined a@Alias {} args) = structFieldDescriptorTypeName java (resolveAlias a args)
+        typeName (BT_Maybe t) = [lt|org.bondlib.StructBondType.SomethingObjectStructField<#{getElementTypeName java t}>|]
+        typeName t = [lt|org.bondlib.StructBondType.ObjectStructField<#{getElementTypeName java t}>|]
+
+
+-- given the type of the field, value indicating whether a struct field descriptor type is generic and hence needs an explicit type parameter
+isGenericStructFieldDescriptor :: Type -> Bool
+isGenericStructFieldDescriptor (BT_Maybe t) = not (isPrimitiveNonEnumBondType t)
+isGenericStructFieldDescriptor t = not (isPrimitiveNonEnumBondType t)
+
+
+-- given a type parameter, returns the name of a local variable containing the type descriptor
+typeParamVarName :: TypeParam -> Text
+typeParamVarName TypeParam {..} = [lt|#{paramName}|]
+
+
+-- given a type parameter, returns the declaration of a local variable containing the type descriptor
+typeParamVarDecl :: TypeParam -> Text
+typeParamVarDecl t@TypeParam {..} = [lt|org.bondlib.BondType<#{paramName}> #{typeParamVarName t}|]
+
+
+-- given a list of type parameters, returns it as comma-separated text
+typeParamNameList :: [TypeParam] -> Text
+typeParamNameList declParams = [lt|#{sepBy ", " paramName declParams}|]
+
+
+-- given a list of type parameter, returns a comma-separated list of names of local variables containing the type descriptor
+typeParamVarNameList :: [TypeParam] -> Text
+typeParamVarNameList declParams = [lt|#{sepBy ", " typeParamVarName declParams}|]
+
+
+-- given a list of type parameter, returns a comma-separated list of declarations of local variables containing the type descriptor
+typeParamVarDeclList :: [TypeParam] -> Text
+typeParamVarDeclList declParams = [lt|#{sepBy ", " typeParamVarDecl declParams}|]
+
+
+-- given a list of type parameters, returns it as comma-separated text with angles (unless the list is empty)
+typeParamAnglesNameList :: [TypeParam] -> Text
+typeParamAnglesNameList declParams = [lt|#{angles $ typeParamNameList declParams}|]
+
+
+-- given a class name and a list of type parameters, returns the full type name with type parameters (if any)
+typeNameWithParams :: String -> [TypeParam] -> Text
+typeNameWithParams declName declParams = [lt|#{declName}#{typeParamAnglesNameList declParams}|]
+
+
+-- given a class name and a list of type parameters, returns the full type descriptor name with type parameters (if any)
+typeDescriptorNameWithParams :: String -> [TypeParam] -> Text
+typeDescriptorNameWithParams declName declParams = [lt|org.bondlib.StructBondType<#{typeNameWithParams declName declParams}>|]
+
+
+-- given a class name, returns the full type descriptor name (using non-generic notation for the struct type)
+typeDescriptorName :: String -> Text
+typeDescriptorName declName = [lt|org.bondlib.StructBondType<#{declName}>|]
+
+
+-- given a variable name, returns call to ArgumentHelper.ensureNotNull method that checks the variable for null
+ensureNotNullArgument :: Text -> Text
+ensureNotNullArgument argName = [lt|org.bondlib.ArgumentHelper.ensureNotNull(#{argName}, "#{argName}")|]
+
+
+-- given a field type and optional default value, returns an expression for the parameter containing the default value,
+-- along with the leading comma; this value is used in initialization of struct field descriptors where
+-- the constructors are overloaded to take explicit default value or take none (i.e. use the implicit default)
+fieldDefaultValueInitParamExpr :: MappingContext -> Type -> Maybe Default -> Text
+fieldDefaultValueInitParamExpr _ _ (Just (DefaultBool val)) = if val
+    then [lt|, true|]
+    else [lt|, false|]
+fieldDefaultValueInitParamExpr _ BT_Int8 (Just (DefaultInteger val)) = [lt|, (byte)#{val}|]
+fieldDefaultValueInitParamExpr _ BT_Int16 (Just (DefaultInteger val)) = [lt|, (short)#{val}|]
+fieldDefaultValueInitParamExpr _ BT_Int32 (Just (DefaultInteger val)) = [lt|, #{val}|]
+fieldDefaultValueInitParamExpr _ BT_Int64 (Just (DefaultInteger val)) = [lt|, #{val}L|]
+fieldDefaultValueInitParamExpr _ BT_UInt8 (Just (DefaultInteger val)) = [lt|, (byte)#{twosComplement 8 val}|]
+fieldDefaultValueInitParamExpr _ BT_UInt16 (Just (DefaultInteger val)) = [lt|, (short)#{twosComplement 16 val}|]
+fieldDefaultValueInitParamExpr _ BT_UInt32 (Just (DefaultInteger val)) = [lt|, #{twosComplement 32 val}|]
+fieldDefaultValueInitParamExpr _ BT_UInt64 (Just (DefaultInteger val)) = [lt|, #{twosComplement 64 val}L|]
+fieldDefaultValueInitParamExpr _ BT_Float (Just (DefaultFloat val)) = [lt|, #{val}F|]
+fieldDefaultValueInitParamExpr _ BT_Float (Just (DefaultInteger val)) = [lt|, #{val}F|]
+fieldDefaultValueInitParamExpr _ BT_Double (Just (DefaultFloat val)) = [lt|, #{val}D|]
+fieldDefaultValueInitParamExpr _ BT_Double (Just (DefaultInteger val)) = [lt|, #{val}D|]
+fieldDefaultValueInitParamExpr _ BT_String (Just (DefaultString val)) = [lt|, "#{val}"|]
+fieldDefaultValueInitParamExpr _ BT_WString (Just (DefaultString val)) = [lt|, "#{val}"|]
+fieldDefaultValueInitParamExpr java (BT_UserDefined e@Enum {..} _) (Just (DefaultEnum val)) = [lt|, #{qualifiedDeclaredTypeName java e}.#{val}|]
+fieldDefaultValueInitParamExpr _ _ _ = mempty
+
+
+-- given a struct name and type parameters, and type, returns a type descriptor expression for the field, used in initialization of struct field descriptors
+structFieldDescriptorInitStructExpr :: MappingContext -> Type -> String -> [Type] -> Text
+structFieldDescriptorInitStructExpr java fieldType typeName params = [lt|#{typeCastExpr} getStructType(#{typeName}.class#{paramExprList params})|]
+    where
+        typeCastExpr = [lt|(org.bondlib.StructBondType<#{(getTypeName java) fieldType}>)|]
+        paramExprList :: [Type] -> Text
+        paramExprList [] = mempty
+        paramExprList (x:xs) = [lt|, #{structFieldDescriptorInitTypeExpr java x}#{paramExprList xs}|]
+
+
+-- given field type, returns a type descriptor expression for the field, used in initialization of struct field descriptors
+structFieldDescriptorInitTypeExpr :: MappingContext -> Type -> Text
+structFieldDescriptorInitTypeExpr java (BT_Maybe t) = structFieldDescriptorInitTypeExpr java t
+structFieldDescriptorInitTypeExpr _ BT_Int8 = [lt|org.bondlib.BondTypes.INT8|]
+structFieldDescriptorInitTypeExpr _ BT_Int16 = [lt|org.bondlib.BondTypes.INT16|]
+structFieldDescriptorInitTypeExpr _ BT_Int32 = [lt|org.bondlib.BondTypes.INT32|]
+structFieldDescriptorInitTypeExpr _ BT_Int64 = [lt|org.bondlib.BondTypes.INT64|]
+structFieldDescriptorInitTypeExpr _ BT_UInt8 = [lt|org.bondlib.BondTypes.UINT8|]
+structFieldDescriptorInitTypeExpr _ BT_UInt16 = [lt|org.bondlib.BondTypes.UINT16|]
+structFieldDescriptorInitTypeExpr _ BT_UInt32 = [lt|org.bondlib.BondTypes.UINT32|]
+structFieldDescriptorInitTypeExpr _ BT_UInt64 = [lt|org.bondlib.BondTypes.UINT64|]
+structFieldDescriptorInitTypeExpr _ BT_Float = [lt|org.bondlib.BondTypes.FLOAT|]
+structFieldDescriptorInitTypeExpr _ BT_Double = [lt|org.bondlib.BondTypes.DOUBLE|]
+structFieldDescriptorInitTypeExpr _ BT_Bool = [lt|org.bondlib.BondTypes.BOOL|]
+structFieldDescriptorInitTypeExpr _ BT_String = [lt|org.bondlib.BondTypes.STRING|]
+structFieldDescriptorInitTypeExpr _ BT_WString = [lt|org.bondlib.BondTypes.WSTRING|]
+structFieldDescriptorInitTypeExpr _ BT_Blob = [lt|org.bondlib.BondTypes.BLOB|]
+structFieldDescriptorInitTypeExpr java (BT_Bonded t) = [lt|bondedOf(#{structFieldDescriptorInitTypeExpr java t})|]
+structFieldDescriptorInitTypeExpr java (BT_Nullable t) = [lt|nullableOf(#{structFieldDescriptorInitTypeExpr java t})|]
+structFieldDescriptorInitTypeExpr java (BT_Vector t) = [lt|vectorOf(#{structFieldDescriptorInitTypeExpr java t})|]
+structFieldDescriptorInitTypeExpr java (BT_List t) = [lt|listOf(#{structFieldDescriptorInitTypeExpr java t})|]
+structFieldDescriptorInitTypeExpr java (BT_Set t) = [lt|setOf(#{structFieldDescriptorInitTypeExpr java t})|]
+structFieldDescriptorInitTypeExpr java (BT_Map k v) = [lt|mapOf(#{structFieldDescriptorInitTypeExpr java k}, #{structFieldDescriptorInitTypeExpr java v})|]
+structFieldDescriptorInitTypeExpr _ (BT_TypeParam param) = [lt|#{paramName param}|]
+structFieldDescriptorInitTypeExpr java (BT_UserDefined e@Enum {} _) = [lt|#{qualifiedDeclaredTypeName java e}.BOND_TYPE|]
+structFieldDescriptorInitTypeExpr java t@(BT_UserDefined s@Struct {} params) = [lt|#{structFieldDescriptorInitStructExpr java t (qualifiedDeclaredTypeName java s) params}|]
+structFieldDescriptorInitTypeExpr java t@(BT_UserDefined s@Forward {} params) = [lt|#{structFieldDescriptorInitStructExpr java t (qualifiedDeclaredTypeName java s) params}|]
+structFieldDescriptorInitTypeExpr java (BT_UserDefined a@Alias {} params) = structFieldDescriptorInitTypeExpr java (resolveAlias a params)
+structFieldDescriptorInitTypeExpr _ t = error $ "invalid declaration type for structFieldDescriptorInitTypeExpr: " ++ show t
+
+
+-- given struct base type, returns a type descriptor expression
+structBaseDescriptorInitStructExpr :: MappingContext -> Maybe Type -> Text
+structBaseDescriptorInitStructExpr java t = maybe [lt|null|] (structFieldDescriptorInitTypeExpr java) t
+
+
+-- given struct class name and generic type parameters, builds text for GenericBondTypeBuilder abstract class
+-- that defines the public API to specialize a generic struct to specific generic type arguments
+-- (this class is generated only when the enclosing Bond struct class is generic)
+makeStructMember_GenericBondTypeBuilder :: String -> [TypeParam] -> Text
+makeStructMember_GenericBondTypeBuilder declName declParams = [lt|
+    public static abstract class GenericBondTypeBuilder {
+
+        private GenericBondTypeBuilder() {
+        }
+
+        public abstract #{typeParamAnglesNameList declParams} #{typeDescriptorNameWithParams declName declParams} makeGenericType(#{typeParamVarDeclList declParams});
+    }
+|]
+
+
+-- given struct class name and generic type parameters, builds text for implementation
+-- of the StructBondTypeBuilderImpl.makeGenericType method
+-- (this method is generated only when the enclosing Bond struct class is generic)
+makeStructBuilderMember_makeGenericType :: String -> [TypeParam] -> Text
+makeStructBuilderMember_makeGenericType declName declParams = [lt|
+            private #{typeParamAnglesNameList declParams} #{typeDescriptorNameWithParams declName declParams} makeGenericType(#{typeParamVarDeclList declParams}) {
+                #{newlineSepEnd 4 checkArg declParams}return #{castExpr} this.getInitializedFromCache(#{typeParamVarNameList declParams});
+            }
+|]
+    where
+        checkArg t@TypeParam {..} = [lt|#{ensureNotNullArgument (typeParamVarName t)};|]
+        castExpr = [lt|(StructBondTypeImpl)|]
+
+
+-- given struct class name and generic type parameters, builds text for implementation of
+-- the StructBondTypeBuilderImpl class which is responsible for building the type descriptor
+makeStructBondTypeMember_StructBondTypeBuilderImpl :: String -> [TypeParam] -> Text
+makeStructBondTypeMember_StructBondTypeBuilderImpl declName declParams = [lt|
+        static final class StructBondTypeBuilderImpl extends org.bondlib.StructBondType.StructBondTypeBuilder<#{declName}> {
+            #{ifThenElse (null declParams) mempty (makeStructBuilderMember_makeGenericType declName declParams)}
+            @Override
+            public final int getGenericTypeParameterCount() {
+                return #{length declParams};
+            }
+
+            @Override
+            protected final #{typeDescriptorName declName} buildNewInstance(org.bondlib.BondType[] genericTypeArguments) {
+                return new StructBondTypeImpl(#{ifThenElse (null declParams) nullText "new org.bondlib.GenericTypeSpecialization(genericTypeArguments)"});
+            }
+
+            static void register() {
+                registerStructType(#{declName}.class, new StructBondTypeBuilderImpl());
+            }
+        }|]
+    where
+        nullText = "null" :: Text
+
+
+-- given generic type parameters, struct fields, and base type, builds text for implementation of
+-- the StructBondTypeImpl.initialize method
+makeStructBondTypeMember_initialize :: MappingContext -> [TypeParam] -> [Field] -> Maybe Type -> Text
+makeStructBondTypeMember_initialize java declParams structFields structBase = [lt|
+        @Override
+        protected final void initialize() {#{typeArgVarDeclList}#{fieldDescriptorInitList}
+            super.initializeBaseAndFields(#{baseTypeDescriptorParam}#{fieldTypeDescriptorParamsSeparator}#{fieldTypeDescriptorParams});
+        }|]
+    where
+        typeArgVarDeclList = newlineBeginSep 3 typeArgVarDecl indexedDeclParams
+        typeArgVarDecl (index, typeParam) = [lt|#{typeParamVarDecl typeParam} = this.getGenericSpecialization().getGenericTypeArgument(#{index});|]
+        indexedDeclParams = zip [0 :: Int ..] declParams
+
+        fieldDescriptorInitList = newlineBeginSep 3 fieldDescriptorInit structFields
+        fieldDescriptorInit Field {..} = [lt|this.#{fieldName} = new #{structFieldDescriptorTypeName java fieldType}(#{constructorParams});|]
+          where
+            constructorParams = [lt|this#{fieldTypeParam}, #{fieldOrdinal}, "#{fieldName}", #{modifierConstantName fieldModifier}#{fieldDefaultValueParam}|]
+            fieldTypeParam = if isGenericStructFieldDescriptor fieldType
+                then [lt|, #{structFieldDescriptorInitTypeExpr java fieldType}|]
+                else mempty
+            fieldDefaultValueParam = fieldDefaultValueInitParamExpr java fieldType fieldDefault
+
+        baseTypeDescriptorParam = structBaseDescriptorInitStructExpr java structBase
+        fieldTypeDescriptorParamsSeparator = ifThenElse (null structFields) mempty [lt|, |]
+        fieldTypeDescriptorParams = sepBy ", " structFieldReference structFields
+        structFieldReference Field {..} = [lt|this.#{fieldName}|]
+
+
+-- given struct class name, generic type parameters, and struct fields, builds text for implementation of
+-- the StructBondTypeImpl.serializeStructFields method
+makeStructBondTypeMember_serializeStructFields :: String -> [TypeParam] -> [Field] -> Text
+makeStructBondTypeMember_serializeStructFields declName declParams structFields = [lt|
+        @Override
+        protected final void serializeStructFields(#{methodParamDecl}) throws java.io.IOException {#{newlineBeginSep 3 serializeField structFields}
+        }|]
+            where
+                methodParamDecl = [lt|org.bondlib.BondType.SerializationContext context, #{typeNameWithParams declName declParams} value|]
+                serializeField Field {..} = [lt|this.#{fieldName}.serialize(context, value.#{fieldName});|]
+
+
+-- given struct class name, generic type parameters, and struct fields, builds text for implementation of
+-- the StructBondTypeImpl.deserializeStructFields method for TaggedProtocolReaders
+makeStructBondTypeMember_deserializeStructFields_tagged :: String -> [TypeParam] -> [Field] -> Text
+makeStructBondTypeMember_deserializeStructFields_tagged declName declParams structFields = [lt|
+        @Override
+        protected final void deserializeStructFields(#{methodParamDecl}) throws java.io.IOException {#{newlineBeginSep 3 declareLocalVariable structFields}
+            while (this.readField(context)) {
+                switch (context.readFieldResult.id) {#{newlineBeginSep 5 deserializeField structFields}
+                    default:
+                        context.reader.skip(context.readFieldResult.type);
+                        break;
+                }
+            }#{newlineBeginSep 3 verifyField structFields}
+        }|]
+            where
+                methodParamDecl = [lt|org.bondlib.BondType.TaggedDeserializationContext context, #{typeNameWithParams declName declParams} value|]
+                declareLocalVariable Field {..} = [lt|boolean __has_#{fieldName} = false;|]
+                deserializeField Field {..} = [lt|#{switchCasePart}#{newLine 6}#{deserializePart}#{newLine 6}#{setBooleanPart}#{newLine 6}break;|]
+                  where
+                    switchCasePart = [lt|case #{fieldOrdinal}:|]
+                    deserializePart = [lt|value.#{fieldName} = this.#{fieldName}.deserialize(context, __has_#{fieldName});|]
+                    setBooleanPart = [lt|__has_#{fieldName} = true;|]
+
+                verifyField Field {..} = [lt|this.#{fieldName}.verifyDeserialized(__has_#{fieldName});|]
+
+
+-- given struct class name, generic type parameters, and struct fields, builds text for implementation of
+-- the StructBondTypeImpl.deserializeStructFields method for UntaggedProtocolReaders
+makeStructBondTypeMember_deserializeStructFields_untagged :: String -> [TypeParam] -> [Field] -> Text
+makeStructBondTypeMember_deserializeStructFields_untagged declName declParams structFields = [lt|
+        @Override
+        protected final void deserializeStructFields(#{methodParamDecl}) throws java.io.IOException {#{newlineBeginSep 3 declareLocalVariable structFields}
+            for (final org.bondlib.FieldDef field : structDef.fields) {
+                switch (field.id) {#{newlineBeginSep 5 deserializeField structFields}
+                    default:
+                        context.reader.skip(context.schema, field.type);
+                        break;
+                }
+            }#{newlineBeginSep 3 verifyField structFields}
+        }|]
+            where
+                methodParamDecl = [lt|org.bondlib.BondType.UntaggedDeserializationContext context, org.bondlib.StructDef structDef, #{typeNameWithParams declName declParams} value|]
+                declareLocalVariable Field {..} = [lt|boolean __has_#{fieldName} = false;|]
+                deserializeField Field {..} = [lt|#{switchCasePart}#{newLine 6}#{deserializePart}#{newLine 6}#{setBooleanPart}#{newLine 6}break;|]
+                  where
+                    switchCasePart = [lt|case #{fieldOrdinal}:|]
+                    deserializePart = [lt|value.#{fieldName} = this.#{fieldName}.deserialize(context, field.type);|]
+                    setBooleanPart = [lt|__has_#{fieldName} = true;|]
+
+                verifyField Field {..} = [lt|this.#{fieldName}.verifyDeserialized(__has_#{fieldName});|]
+
+
+-- given class name, generic type parameters, and struct fields, builds text for implementation of
+-- the StructBondTypeImpl.initializeStructFields method
+makeStructBondTypeMember_initializeStructFields :: String -> [TypeParam] -> [Field] -> Text
+makeStructBondTypeMember_initializeStructFields declName declParams structFields = [lt|
+        @Override
+        protected final void initializeStructFields(#{methodParamDecl}) {#{newlineBeginSep 3 initializeField structFields}
+        }|]
+            where
+                methodParamDecl = [lt|#{typeNameWithParams declName declParams} value|]
+                initializeField Field {..} = [lt|value.#{fieldName} = this.#{fieldName}.initialize();|]
+
+
+-- given class name, generic type parameters, and struct fields, builds text for implementation of
+-- the StructBondTypeImpl.copyStructFields method
+makeStructBondTypeMember_cloneStructFields :: String -> [TypeParam] -> [Field] -> Text
+makeStructBondTypeMember_cloneStructFields declName declParams structFields = [lt|
+        @Override
+        protected final void cloneStructFields(#{methodParamDecl}) {#{newlineBeginSep 3 cloneField structFields}
+        }|]
+            where
+                methodParamDecl = [lt|#{typeNameWithParams declName declParams} fromValue, #{typeNameWithParams declName declParams} toValue|]
+                cloneField Field {..} = [lt|toValue.#{fieldName} = this.#{fieldName}.clone(fromValue.#{fieldName});|]
+
+
+-- builds text for anonymous implementation of the GenericBondTypeBuilder abstract class and assignment to the BOND_TYPE variable
+bondTypeStaticVariableDeclAsGenericBondTypeBuilder :: String -> [TypeParam] -> Text
+bondTypeStaticVariableDeclAsGenericBondTypeBuilder declName declParams = [lt|public static final GenericBondTypeBuilder BOND_TYPE = new GenericBondTypeBuilder() {
+
+        final StructBondTypeImpl.StructBondTypeBuilderImpl builder = new StructBondTypeImpl.StructBondTypeBuilderImpl();
+
+        @Override
+        public final <#{paramList}> org.bondlib.StructBondType<#{declName}<#{paramList}>> makeGenericType(#{sepBy ", " methodArg declParams}) {
+            return this.builder.makeGenericType(#{paramList});
+        }
+    };|]
+    where
+        paramList = sepBy ", " paramName declParams
+        methodArg TypeParam {..} = [lt|org.bondlib.BondType<#{paramName}> #{paramName}|]
+
+
+-- builds text for public constructor of non-generic Bond struct class
+publicConstructorDeclForNonGenericStruct :: MappingContext -> String -> Maybe Type -> Text
+publicConstructorDeclForNonGenericStruct java declName maybeBase = [lt|
+    public #{declName}() {
+        super(#{superConstructorArgs maybeBase});
+        ((StructBondTypeImpl)BOND_TYPE).initializeStructFields(this);
+    };
+|]
+    where
+        superConstructorArgs Nothing = mempty
+        superConstructorArgs (Just t) = if isGenericBondStructType t
+            then [lt|(org.bondlib.StructBondType<#{getTypeName java t}>)BOND_TYPE.getBaseStructType()|]
+            else mempty
+
+
+-- builds text for public constructor of generic Bond struct class
+publicConstructorDeclForGenericStruct :: MappingContext -> String -> [TypeParam] -> Maybe Type -> Text
+publicConstructorDeclForGenericStruct java declName declParams maybeBase = [lt|
+public #{declName}(org.bondlib.StructBondType<#{declName}<#{paramList}>> genericType) {
+        super(#{superConstructorArgs maybeBase});
+        this.__genericType = (StructBondTypeImpl<#{paramList}>)genericType;
+        this.__genericType.initializeStructFields(this);
+    };
+|]
+    where
+        paramList = sepBy ", " paramName declParams
+        superConstructorArgs Nothing = mempty
+        superConstructorArgs (Just t) = if isGenericBondStructType t
+            then [lt|(org.bondlib.StructBondType<#{getTypeName java t}>)org.bondlib.ArgumentHelper.ensureNotNull(genericType, "genericType").getBaseStructType()|]
+            else mempty
+
+
+-- builds text for Object.equals(Object) override
+object_equals :: String -> [Field] -> Maybe Type -> Text
+object_equals declName fields structBase = [lt|@Override
+    public boolean equals(Object o) {
+        if (!(o instanceof #{declName})) return false;
+        #{compareBase structBase}
+        final #{declName} other = (#{declName}) o;
+        #{newlineSep 2 compareField fields}
+        return true;
+    }
+|]
+    where
+        compareBase (Just _)     = [lt|if (!(super.equals(o))) return false;|]
+        compareBase Nothing      = mempty
+        compareField Field {..}  = [lt|if (!(#{equalsMember fieldType fieldName})) return false;|]
+        equalsMember BT_Float f  = [lt|org.bondlib.FloatingPointHelper.floatEquals(this.#{f}, other.#{f})|]
+        equalsMember BT_Double f = [lt|org.bondlib.FloatingPointHelper.doubleEquals(this.#{f}, other.#{f})|]
+        equalsMember BT_Bool f    = [lt|this.#{f} == other.#{f}|]
+        equalsMember BT_Int8 f    = [lt|this.#{f} == other.#{f}|]
+        equalsMember BT_Int16 f   = [lt|this.#{f} == other.#{f}|]
+        equalsMember BT_Int32 f   = [lt|this.#{f} == other.#{f}|]
+        equalsMember BT_Int64 f   = [lt|this.#{f} == other.#{f}|]
+        equalsMember BT_UInt8 f   = [lt|this.#{f} == other.#{f}|]
+        equalsMember BT_UInt16 f  = [lt|this.#{f} == other.#{f}|]
+        equalsMember BT_UInt32 f  = [lt|this.#{f} == other.#{f}|]
+        equalsMember BT_UInt64 f  = [lt|this.#{f} == other.#{f}|]
+        equalsMember (BT_UserDefined a@Alias {} args) f = equalsMember (resolveAlias a args) f
+        equalsMember _ f          = [lt|(this.#{f} == null && other.#{f} == null) || (this.#{f} != null && this.#{f}.equals(other.#{f}))|]
+
+
+-- builds text for Object.hashCode() override
+object_hashCode :: [Field] -> Maybe Type -> Text
+object_hashCode fields structBase = [lt|@Override
+    public int hashCode() {
+        int result = 17;
+        #{newlineSep 2 hash hashInputs}
+        return result;
+    }
+|]
+    where
+        hash codeExpr = [lt|result += #{codeExpr};
+        result *= 0xeadbeef;
+        result ^= result >> 16;|]
+
+        hashInputs = (hashBase structBase) ++ hashFields
+
+        hashBase (Just _) = [[lt|super.hashCode()|]]
+        hashBase Nothing  = []
+
+        hashFields = map (\Field {..} -> hashCode fieldType fieldName) fields
+        hashCode BT_Bool f    = [lt|(#{f} ? 0 : 1)|]
+        hashCode BT_Int64 f   = [lt|#{f} ^ (#{f} >>> 32)|]
+        hashCode BT_UInt64 f  = [lt|#{f} ^ (#{f} >>> 32)|]
+        hashCode BT_Float f   = [lt|org.bondlib.FloatingPointHelper.floatHashCode(#{f})|]
+        hashCode BT_Double f  = [lt|org.bondlib.FloatingPointHelper.doubleHashCode(#{f})|]
+        hashCode BT_Int8 f    = [lt|#{f}|]
+        hashCode BT_Int16 f   = [lt|#{f}|]
+        hashCode BT_Int32 f   = [lt|#{f}|]
+        hashCode BT_UInt8 f   = [lt|#{f}|]
+        hashCode BT_UInt16 f  = [lt|#{f}|]
+        hashCode BT_UInt32 f  = [lt|#{f}|]
+        hashCode (BT_UserDefined a@Alias {} args) f = hashCode (resolveAlias a args) f
+        hashCode _ f          = [lt|#{f} == null ? 0 : #{f}.hashCode()|]
+
+
+-- We implement Externalizable, rather than Serializable, so that
+-- ser/deserialization will result in a single call on the most derived class,
+-- rather than one call for each type in the inheritance chain. By reading into
+-- a byte[] instead of trying to deserialize from the ObjectInput{,Stream} we're
+-- passed, we can start from a ByteArrayInputStream, which we already know how
+-- to clone for Bonded fields.
+--
+-- We write the length of the serialized data because we can't assume the
+-- ObjectInput{,Stream} actually ends after the object we care about.
+--
+-- serialVersionUID is always 0 so that Java will always delegate compatibility
+-- checking of serialized data against current deserialization code to us.
+javaNativeSerializationGlue :: String -> Text
+javaNativeSerializationGlue declName = [lt|
+    // Java native serialization
+    private static final long serialVersionUID = 0L;
+    private #{declName} __deserializedInstance;
+
+    @Override
+    public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
+        final java.io.ByteArrayOutputStream outStream = new java.io.ByteArrayOutputStream();
+        final org.bondlib.ProtocolWriter writer = new org.bondlib.CompactBinaryWriter(outStream, 1);
+        org.bondlib.Marshal.marshal(this, writer);
+
+        final byte[] marshalled = outStream.toByteArray();
+        out.write(0);   // This type is not generic and has zero type parameters.
+        out.writeInt(marshalled.length);
+        out.write(marshalled);
+    }
+
+    @Override
+    public void readExternal(java.io.ObjectInput in) throws java.io.IOException, java.lang.ClassNotFoundException {
+        if (in.read() != 0) throw new java.io.IOException("type is not generic, but serialized data has type parameters.");
+        final int marshalledLength = in.readInt();
+        final byte[] marshalled = new byte[marshalledLength];
+        in.readFully(marshalled);
+
+        final java.io.ByteArrayInputStream inStream = new java.io.ByteArrayInputStream(marshalled);
+        this.__deserializedInstance = org.bondlib.Unmarshal.unmarshal(inStream, getBondType()).deserialize();
+    }
+
+    private Object readResolve() throws java.io.ObjectStreamException {
+        return this.__deserializedInstance;
+    }
+    // end Java native serialization
+    |]
+
+
+javaNativeSerializationUnimpl :: Text
+javaNativeSerializationUnimpl = [lt|
+    // Java native serialization
+    @Override
+    public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
+        throw new java.lang.IllegalArgumentException("java.io.Serializable support is not implemented for generic types");
+    }
+
+    @Override
+    public void readExternal(java.io.ObjectInput in) throws java.io.IOException, java.lang.ClassNotFoundException {
+        // This may actually fail before reaching this line with an InvalidClassException because
+        // generic types don't have the nullary constructor required by the Java serialization
+        // framework.
+        throw new java.lang.IllegalArgumentException("java.io.Serializable support is not implemented for generic types");
+    }
+    // end Java native serialization
+    |]
+
+-- Template for struct -> Java class.
+class_java :: MappingContext -> [Import] -> Declaration -> Text
+class_java java _ declaration = [lt|
+package #{javaPackage};
+#{typeDefinition declaration}
+|]
+    where
+        javaType = getTypeName java
+        javaPackage = sepBy "." toText $ getNamespace java
+
+        -- struct -> Java class
+        typeDefinition s@Struct {..} = [lt|
+#{generatedClassAnnotations}
+public class #{typeNameWithParams declName declParams}#{maybe interface baseClass structBase} {
+    #{ifThenElse (null declParams) mempty (makeStructMember_GenericBondTypeBuilder declName declParams)}
+    private static final class StructBondTypeImpl#{typeParamAnglesNameList declParams} extends #{typeDescriptorNameWithParams declName declParams} {
+        #{makeStructBondTypeMember_StructBondTypeBuilderImpl declName declParams}
+
+        #{doubleLineSep 2 fieldDescriptorFieldDecl structFields}
+
+        private StructBondTypeImpl(org.bondlib.GenericTypeSpecialization genericTypeSpecialization) {
+            super(genericTypeSpecialization);
+        }
+        #{makeStructBondTypeMember_initialize java declParams structFields structBase}
+
+        @Override
+        public final java.lang.String getName() {
+            return "#{declName}";
+        }
+
+        @Override
+        public final java.lang.String getQualifiedName() {
+            return "#{qualifiedDeclaredTypeName idl s}";
+        }
+
+        @Override
+        public final java.lang.Class<#{typeNameWithParams declName declParams}> getValueClass() {
+            return (java.lang.Class<#{typeNameWithParams declName declParams}>) (java.lang.Class) #{declName}.class;
+        }
+
+        @Override
+        public final #{typeNameWithParams declName declParams} newInstance() {
+            return new #{typeNameWithParams declName declParams}(#{ifThenElse (null declParams) mempty thisText});
+        }
+        #{makeStructBondTypeMember_serializeStructFields declName declParams structFields}
+        #{makeStructBondTypeMember_deserializeStructFields_tagged declName declParams structFields}
+        #{makeStructBondTypeMember_deserializeStructFields_untagged declName declParams structFields}
+        #{makeStructBondTypeMember_initializeStructFields declName declParams structFields}
+        #{makeStructBondTypeMember_cloneStructFields declName declParams structFields}
+    }
+
+    #{bondTypeStaticVariableDecl}
+
+    public static void initializeBondType() {
+        StructBondTypeImpl.StructBondTypeBuilderImpl.register();
+    }
+
+    static {
+        initializeBondType();
+    }
+    #{bondTypeDescriptorInstanceVariableDecl}
+
+    #{ifThenElse (null declParams) (javaNativeSerializationGlue declName) javaNativeSerializationUnimpl}
+
+    #{doubleLineSep 1 publicFieldDecl structFields}
+    #{publicConstructorDecl}
+    #{object_equals declName structFields structBase}
+    #{object_hashCode structFields structBase}
+    @Override
+    public org.bondlib.StructBondType<? extends #{typeNameWithParams declName declParams}> getBondType() {
+        return #{getBondTypeReturnValue};
+    }
+}|]
+            where
+                idl = MappingContext idlTypeMapping [] [] []
+                interface = [lt| implements org.bondlib.BondSerializable|]
+                baseClass x = [lt| extends #{javaType x}|]
+                publicFieldDecl Field {..} = [lt|public #{javaType fieldType} #{fieldName};|]
+                fieldDescriptorFieldDecl Field {..} = [lt|private #{structFieldDescriptorTypeName java fieldType} #{fieldName};|]
+                bondTypeStaticVariableDecl = if null declParams
+                    then [lt|public static final org.bondlib.StructBondType<#{declName}> BOND_TYPE = new StructBondTypeImpl.StructBondTypeBuilderImpl().getInitializedFromCache();|]
+                    else bondTypeStaticVariableDeclAsGenericBondTypeBuilder declName declParams
+                bondTypeDescriptorInstanceVariableDecl = if null declParams
+                    then mempty
+                    else [lt|private final StructBondTypeImpl#{typeParamAnglesNameList declParams} __genericType;|]
+                getBondTypeReturnValue = if null declParams
+                    then [lt|BOND_TYPE|]
+                    else [lt|this.__genericType|]
+                publicConstructorDecl = if null declParams
+                    then publicConstructorDeclForNonGenericStruct java declName structBase
+                    else publicConstructorDeclForGenericStruct java declName declParams structBase
+
+                thisText = "this" :: Text
+
+        typeDefinition _ = mempty
diff --git a/src/Language/Bond/Codegen/Java/Enum_java.hs b/src/Language/Bond/Codegen/Java/Enum_java.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/Bond/Codegen/Java/Enum_java.hs
@@ -0,0 +1,143 @@
+-- Copyright (c) Microsoft. All rights reserved.
+-- Licensed under the MIT license. See LICENSE file in the project root
+-- for full license information.
+
+{-# LANGUAGE QuasiQuotes, OverloadedStrings, RecordWildCards #-}
+
+module Language.Bond.Codegen.Java.Enum_java
+    ( enum_java
+    ) where
+
+import Prelude
+import Data.Text.Lazy (Text)
+import Text.Shakespeare.Text
+import Language.Bond.Syntax.Types
+import Language.Bond.Util
+import Language.Bond.Codegen.TypeMapping
+import Language.Bond.Codegen.Util
+import qualified Language.Bond.Codegen.Java.Util as Java
+
+-- Template for enum -> Java enum-like class.
+enum_java :: MappingContext -> Declaration -> Text
+enum_java java declaration = [lt|
+package #{javaPackage};
+
+#{typeDefinition declaration}
+|]
+  where
+    javaPackage = sepBy "." toText $ getNamespace java
+
+    typeDefinition Enum {..} = [lt|
+#{Java.generatedClassAnnotations}
+public final class #{declName} implements org.bondlib.BondEnum<#{declName}> {
+
+    public static final class Values {
+        private Values() {}
+
+        #{newlineSep 2 constantIntValueDecl enumConstantsWithInt}
+    }
+
+    private static final class EnumBondTypeImpl extends org.bondlib.EnumBondType<#{declName}> {
+
+        @Override
+        public java.lang.Class<#{declName}> getValueClass() { return #{declName}.class; }
+
+        @Override
+        public final #{declName} getEnumValue(int value) { return get(value); }
+    }
+
+    public static final org.bondlib.EnumBondType<#{declName}> BOND_TYPE = new EnumBondTypeImpl();
+
+    #{newlineSep 1 constantObjectDecl enumConstantsWithInt}
+
+    public final int value;
+
+    private final java.lang.String label;
+
+    private #{declName}(int value, java.lang.String label) { this.value = value; this.label = label; }
+
+    @Override
+    public final int getValue() { return this.value; }
+
+    @Override
+    public final java.lang.String getLabel() { return this.label; }
+
+    @Override
+    public final org.bondlib.EnumBondType<#{declName}> getBondType() { return BOND_TYPE; }
+
+    @Override
+    public final int compareTo(#{declName} o) { return this.value < o.value ? -1 : (this.value > o.value ? 1 : 0); }
+
+    @Override
+    public final boolean equals(java.lang.Object other) { return (other instanceof #{declName}) && (this.value == ((#{declName}) other).value); }
+
+    @Override
+    public final int hashCode() { return this.value; }
+
+    @Override
+    public final java.lang.String toString() { return this.label != null ? this.label : ("#{declName}(" + java.lang.String.valueOf(this.value) + ")"); }
+
+    public static #{declName} get(int value) {
+        switch (value) {
+            #{newlineSep 3 switchCaseConstantMapping enumConstantsWithIntDistinct}
+            default: return new #{declName}(value, null);
+        }
+    }
+
+    public static #{declName} valueOf(java.lang.String str) {
+        if (str == null) {
+            throw new java.lang.IllegalArgumentException("Argument 'str' must not be null.");
+        #{newlineSepEnd 2 parseCaseConstantMapping enumConstants}} else {
+            throw new java.lang.IllegalArgumentException("Invalid '#{declName}' enum value: '" + str + "'.");
+        }
+    }
+}|]
+      where
+        -- constant object
+        constantObjectDecl c@Constant {..} =
+            [lt|public static final #{declName} #{constantName} = #{enumObjectAssigmentValue c};|]
+
+        -- constant int
+        constantIntValueDecl Constant {..} = let value x = [lt|#{x}|] in
+            [lt|public static final int #{constantName} = #{optional value constantValue};|]
+
+        -- switch cases that map int to object
+        switchCaseConstantMapping Constant {..} =
+            [lt|case Values.#{constantName}: return #{constantName};|]
+
+        -- parse cases that map string to object
+        parseCaseConstantMapping Constant {..} =
+            [lt|} else if (str.equals("#{constantName}")) {
+            return #{constantName};|]
+
+        -- Process constants to make sure every constant value is set (either explicit or auto-generated).
+        -- TODO: auto-generation of constant values should be handled earlier, once for all languages.
+        enumConstantsWithInt = fixEnumWithInt 0 enumConstants []
+
+        fixEnumWithInt :: Int -> [Constant] -> [Constant] -> [Constant]
+        fixEnumWithInt _ [] result = reverse result
+        fixEnumWithInt nextInt (h:r) result = case constantValue h of
+          Just n -> let fixedN = (fromInteger (Java.twosComplement 32 (toInteger n))) in
+            fixEnumWithInt (fixedN + 1) r ((Constant (constantName h) (Just fixedN)):result)
+          Nothing -> fixEnumWithInt (nextInt + 1) r ((Constant (constantName h) (Just nextInt)):result)
+
+        -- Filter a list of constants, leaving a list of constants with distinct values.
+        -- If several constants in the input list share a value, the first one that appears will be the one that appears in the output list.
+        enumConstantsWithIntDistinct = findEnumConstantsDistinct enumConstantsWithInt []
+
+        findEnumConstantsDistinct :: [Constant] -> [Maybe Int] -> [Constant]
+        findEnumConstantsDistinct [] _ = []
+        findEnumConstantsDistinct (h:r) keys = if elem (constantValue h) keys
+            then findEnumConstantsDistinct r keys
+            else h : findEnumConstantsDistinct r ((constantValue h):keys)
+
+        -- The RHS value to assign to an enum object. If an enum element is the first instance with a particular value,
+        -- this function will return an instantiation. If it isn't, this function will return a reference to the first enum object with the same value.
+        enumObjectAssigmentValue :: Constant -> Text
+        enumObjectAssigmentValue enumConstant =
+            let firstDeclaredEnumConstant = head (filter (\c -> (constantValue c) == (constantValue enumConstant)) enumConstantsWithIntDistinct) in
+                if firstDeclaredEnumConstant == enumConstant
+                    then [lt|new #{declName}(Values.#{constantName enumConstant}, "#{constantName enumConstant}")|]
+                    else [lt|#{constantName firstDeclaredEnumConstant}|]
+
+    typeDefinition _ = mempty
diff --git a/src/Language/Bond/Codegen/Java/Util.hs b/src/Language/Bond/Codegen/Java/Util.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/Bond/Codegen/Java/Util.hs
@@ -0,0 +1,73 @@
+-- Copyright (c) Microsoft. All rights reserved.
+-- Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+{-# LANGUAGE QuasiQuotes, OverloadedStrings, RecordWildCards #-}
+
+module Language.Bond.Codegen.Java.Util
+    ( qualifiedDeclaredTypeName
+    , generatedClassAnnotations
+    , modifierConstantName
+    , isPrimitiveNonEnumBondType
+    , isPrimitiveBondType
+    , isGenericBondStructType
+    , twosComplement
+    ) where
+
+import Prelude
+import Data.List (intercalate)
+import Data.Text.Lazy (Text)
+import Text.Shakespeare.Text
+import Language.Bond.Syntax.Types
+import Language.Bond.Syntax.Util
+import Language.Bond.Codegen.TypeMapping
+import Language.Bond.Codegen.Util()
+
+-- returns the fully qualified name for a declaration
+qualifiedDeclaredTypeName :: MappingContext -> Declaration -> String
+qualifiedDeclaredTypeName java d  = intercalate "." $ getDeclNamespace java d ++ [declName d]
+
+-- returns the Java annotations for a generated class
+generatedClassAnnotations :: Text
+generatedClassAnnotations = [lt|@javax.annotation.Generated("gbc")|]
+
+-- returns the qualified name of Modifier constant
+modifierConstantName :: Modifier -> Text
+modifierConstantName Optional = [lt|org.bondlib.Modifier.Optional|]
+modifierConstantName Required = [lt|org.bondlib.Modifier.Required|]
+modifierConstantName RequiredOptional = [lt|org.bondlib.Modifier.RequiredOptional|]
+
+-- returns a value indicating whether a type is a non-enum Bond primitive type
+isPrimitiveNonEnumBondType :: Type -> Bool
+isPrimitiveNonEnumBondType BT_Int8 = True
+isPrimitiveNonEnumBondType BT_Int16 = True
+isPrimitiveNonEnumBondType BT_Int32 = True
+isPrimitiveNonEnumBondType BT_Int64 = True
+isPrimitiveNonEnumBondType BT_UInt8 = True
+isPrimitiveNonEnumBondType BT_UInt16 = True
+isPrimitiveNonEnumBondType BT_UInt32 = True
+isPrimitiveNonEnumBondType BT_UInt64 = True
+isPrimitiveNonEnumBondType BT_Float = True
+isPrimitiveNonEnumBondType BT_Double = True
+isPrimitiveNonEnumBondType BT_Bool = True
+isPrimitiveNonEnumBondType BT_String = True
+isPrimitiveNonEnumBondType BT_WString = True
+isPrimitiveNonEnumBondType BT_MetaName = True
+isPrimitiveNonEnumBondType BT_MetaFullName = True
+isPrimitiveNonEnumBondType (BT_UserDefined a@Alias {} args) = isPrimitiveNonEnumBondType (resolveAlias a args)
+isPrimitiveNonEnumBondType _ = False
+
+-- returns a value indicating whether a type is a Bond primitive type or enum
+isPrimitiveBondType :: Type -> Bool
+isPrimitiveBondType (BT_UserDefined Enum {..} _) = True
+isPrimitiveBondType t = isPrimitiveNonEnumBondType t
+
+-- returns a value indicating whether a type is a generic struct type with generic type parameters
+isGenericBondStructType :: Type -> Bool
+isGenericBondStructType (BT_UserDefined Struct {..} _) = not (null declParams)
+isGenericBondStructType _ = False
+
+-- takes a bit count and a number and returns its two's complement
+twosComplement :: Integer -> Integer -> Integer
+twosComplement bitCount value = if value < (2 ^ (bitCount - 1))
+    then value
+    else value - (2 ^ bitCount)
diff --git a/src/Language/Bond/Codegen/Templates.hs b/src/Language/Bond/Codegen/Templates.hs
--- a/src/Language/Bond/Codegen/Templates.hs
+++ b/src/Language/Bond/Codegen/Templates.hs
@@ -36,21 +36,20 @@
       -- ** C++
       types_h
     , types_cpp
-    , types_comm_cpp
     , reflection_h
     , enum_h
     , apply_h
     , apply_cpp
     ,  Protocol(..)
-      -- ** C++ Comm
-    , comm_h
       -- ** C#
     , FieldMapping(..)
     , StructMapping(..)
+    , ConstructorOptions(..)
     , types_cs
-    , comm_interface_cs
-    , comm_proxy_cs
-    , comm_service_cs
+      -- ** Java
+    , JavaFieldMapping(..)
+    , class_java
+    , enum_java
     )
     where
 
@@ -60,11 +59,10 @@
 import Language.Bond.Codegen.Cpp.Enum_h
 import Language.Bond.Codegen.Cpp.Reflection_h
 import Language.Bond.Codegen.Cpp.Types_cpp
-import Language.Bond.Codegen.Cpp.Types_Comm_cpp
 import Language.Bond.Codegen.Cpp.Types_h
-import Language.Bond.Codegen.Cpp.Comm_h
 import Language.Bond.Codegen.Cs.Types_cs
-import Language.Bond.Codegen.Cs.Comm_cs
+import Language.Bond.Codegen.Java.Class_java
+import Language.Bond.Codegen.Java.Enum_java
 -- redundant imports for haddock
 import Language.Bond.Codegen.TypeMapping
 import Language.Bond.Syntax.Types
diff --git a/src/Language/Bond/Codegen/TypeMapping.hs b/src/Language/Bond/Codegen/TypeMapping.hs
--- a/src/Language/Bond/Codegen/TypeMapping.hs
+++ b/src/Language/Bond/Codegen/TypeMapping.hs
@@ -23,8 +23,11 @@
     , idlTypeMapping
     , cppTypeMapping
     , cppCustomAllocTypeMapping
+    , cppExpandAliasesTypeMapping
     , csTypeMapping
     , csCollectionInterfacesTypeMapping
+    , javaTypeMapping
+    , javaBoxedTypeMapping
       -- * Alias mapping
       --
       -- | <https://microsoft.github.io/bond/manual/compiler.html#type-aliases Type aliases>
@@ -42,6 +45,7 @@
       -- * Name builders
     , getTypeName
     , getInstanceTypeName
+    , getElementTypeName
     , getAnnotatedTypeName
     , getDeclTypeName
     , getQualifiedName
@@ -52,6 +56,7 @@
       -- * TypeMapping helper functions
     , elementTypeName
     , aliasTypeName
+    , getAliasDeclTypeName
     , declTypeName
     , declQualifiedTypeName
     ) where
@@ -119,12 +124,21 @@
   where
     fix' = fixSyntax $ typeMapping c
 
+getAliasDeclTypeName :: MappingContext -> Declaration -> Builder
+getAliasDeclTypeName c d = fix' $ runReader (aliasDeclTypeName d) c
+  where
+    fix' = fixSyntax $ typeMapping c
+
 -- | Builds the name to be used when instantiating a 'Type'. The instance type
 -- name may be different than the type name returned by 'getTypeName' when the
 -- latter is an interface.
 getInstanceTypeName :: MappingContext -> Type -> Builder
 getInstanceTypeName c t = runReader (instanceTypeName t) c
 
+-- | Builds the name to be used when instantiating an element 'Type'.
+getElementTypeName :: MappingContext -> Type -> Builder
+getElementTypeName c t = runReader (elementTypeName t) c
+
 -- | Builds the annotated name of a 'Type'. The type annotations are used to
 -- express type information about a Bond type that doesn't directly map to
 -- the target language type system (e.g. distinction between a nullable and
@@ -162,17 +176,25 @@
     cppTypeMapping
 
 -- | C++ type name mapping using a custom allocator.
-cppCustomAllocTypeMapping :: ToText a => a -> TypeMapping
-cppCustomAllocTypeMapping alloc = TypeMapping
+cppCustomAllocTypeMapping :: ToText a => Bool -> a -> TypeMapping
+cppCustomAllocTypeMapping scoped alloc = TypeMapping
     (Just Cpp)
     "::"
     "::"
-    (cppTypeCustomAlloc $ toText alloc)
+    (cppTypeCustomAlloc scoped $ toText alloc)
     cppSyntaxFix
-    (cppCustomAllocTypeMapping alloc)
-    (cppCustomAllocTypeMapping alloc)
-    (cppCustomAllocTypeMapping alloc)
+    (cppCustomAllocTypeMapping scoped alloc)
+    (cppCustomAllocTypeMapping scoped alloc)
+    (cppCustomAllocTypeMapping scoped alloc)
 
+cppExpandAliasesTypeMapping :: TypeMapping -> TypeMapping
+cppExpandAliasesTypeMapping m = m
+    { mapType = cppTypeExpandAliases $ mapType m
+    , instanceMapping = cppExpandAliasesTypeMapping $ instanceMapping m
+    , elementMapping = cppExpandAliasesTypeMapping $ elementMapping m
+    , annotatedMapping = cppExpandAliasesTypeMapping $ annotatedMapping m
+    }
+
 -- | The default C# type name mapping.
 csTypeMapping :: TypeMapping
 csTypeMapping = TypeMapping
@@ -212,6 +234,30 @@
     csAnnotatedTypeMapping
     csAnnotatedTypeMapping
 
+-- | The default Java type name mapping.
+javaTypeMapping :: TypeMapping
+javaTypeMapping = TypeMapping
+    (Just Java)
+    ""
+    "."
+    javaType
+    id
+    javaTypeMapping
+    javaBoxedTypeMapping
+    javaTypeMapping
+
+-- | Java type mapping that boxes all primitives.
+javaBoxedTypeMapping :: TypeMapping
+javaBoxedTypeMapping = TypeMapping
+    (Just Java)
+    ""
+    "."
+    javaBoxedType
+    id
+    javaTypeMapping
+    javaBoxedTypeMapping
+    javaTypeMapping
+
 infixr 6 <<>>
 
 (<<>>) :: (Monoid r, Monad m) => m r -> m r -> m r
@@ -243,7 +289,7 @@
 localWith :: (TypeMapping -> TypeMapping) -> TypeNameBuilder -> TypeNameBuilder
 localWith f = local $ \c -> c { typeMapping = f $ typeMapping c }
 
--- | Builder for nested element types (e.g. list elements) in context of 'TypeNameBuilder' monad. 
+-- | Builder for nested element types (e.g. list elements) in context of 'TypeNameBuilder' monad.
 -- Used to implement 'mapType' function of 'TypeMapping'.
 elementTypeName :: Type -> TypeNameBuilder
 elementTypeName = localWith elementMapping . typeName
@@ -303,6 +349,28 @@
     fragment (Fragment s) = pureText s
     fragment (Placeholder i) = typeName $ args !! i
 
+aliasDeclTypeName :: Declaration -> TypeNameBuilder
+aliasDeclTypeName a@Alias {..} = do
+    ctx <- ask
+    case findAliasMapping ctx a of
+        Just AliasMapping {..} -> foldr ((<<>>) . fragment) (pure mempty) aliasTemplate
+        Nothing -> typeName aliasType
+  where
+    fragment (Fragment s) = pureText s
+    fragment (Placeholder i) = pureText $ paramName $ declParams !! i
+aliasDeclTypeName _ = error "aliasDeclTypeName: impossible happened."
+
+-- | Builder for the type alias element name in context of 'TypeNameBuilder' monad.
+aliasElementTypeName :: Declaration -> [Type] -> TypeNameBuilder
+aliasElementTypeName a args = do
+    ctx <- ask
+    case findAliasMapping ctx a of
+        Just AliasMapping {..} -> foldr ((<<>>) . fragment) (pure mempty) aliasTemplate
+        Nothing -> elementTypeName $ resolveAlias a args
+  where
+    fragment (Fragment s) = pureText s
+    fragment (Placeholder i) = elementTypeName $ args !! i
+
 -- IDL type mapping
 idlType :: Type -> TypeNameBuilder
 idlType BT_Int8 = pure "int8"
@@ -360,34 +428,37 @@
 cppType (BT_Map key value) = "std::map<" <>> elementTypeName key <<>> ", " <>> elementTypeName value <<> ">"
 cppType (BT_Bonded type_) = "::bond::bonded<" <>> elementTypeName type_ <<> ">"
 cppType (BT_TypeParam param) = pureText $ paramName param
-cppType (BT_UserDefined a@Alias {..} args) = aliasTypeName a args
 cppType (BT_UserDefined decl args) = declQualifiedTypeName decl <<>> (angles <$> commaSepTypeNames args)
 
 -- C++ type mapping with custom allocator
-cppTypeCustomAlloc :: Builder -> Type -> TypeNameBuilder
-cppTypeCustomAlloc alloc BT_String = pure $ "std::basic_string<char, std::char_traits<char>, typename " <> alloc <> "::rebind<char>::other>"
-cppTypeCustomAlloc alloc BT_WString = pure $ "std::basic_string<wchar_t, std::char_traits<wchar_t>, typename " <> alloc <>  "::rebind<wchar_t>::other>"
-cppTypeCustomAlloc alloc BT_MetaName = cppTypeCustomAlloc alloc BT_String
-cppTypeCustomAlloc alloc BT_MetaFullName = cppTypeCustomAlloc alloc BT_String
-cppTypeCustomAlloc alloc (BT_List element) = "std::list<" <>> elementTypeName element <<>> ", " <>> allocator alloc element <<> ">"
-cppTypeCustomAlloc alloc (BT_Nullable element) | isStruct element = "::bond::nullable<" <>> elementTypeName element <<> ", " <> alloc <> ">"
-cppTypeCustomAlloc _lloc (BT_Nullable element) = "::bond::nullable<" <>> elementTypeName element <<> ">"
-cppTypeCustomAlloc alloc (BT_Vector element) = "std::vector<" <>> elementTypeName element <<>> ", " <>> allocator alloc element <<> ">"
-cppTypeCustomAlloc alloc (BT_Set element) = "std::set<" <>> elementTypeName element <<>> comparer element <<>> allocator alloc element <<> ">"
-cppTypeCustomAlloc alloc (BT_Map key value) = "std::map<" <>> elementTypeName key <<>> ", " <>> elementTypeName value <<>> comparer key <<>> pairAllocator alloc key value <<> ">"
-cppTypeCustomAlloc _ t = cppType t
+cppTypeCustomAlloc :: Bool -> Builder -> Type -> TypeNameBuilder
+cppTypeCustomAlloc scoped alloc BT_String = "std::basic_string<char, std::char_traits<char>, " <>> rebindAllocator scoped alloc (pure "char") <<> " >"
+cppTypeCustomAlloc scoped alloc BT_WString = "std::basic_string<wchar_t, std::char_traits<wchar_t>, " <>> rebindAllocator scoped alloc (pure "wchar_t") <<> " >"
+cppTypeCustomAlloc scoped alloc BT_MetaName = cppTypeCustomAlloc scoped alloc BT_String
+cppTypeCustomAlloc scoped alloc BT_MetaFullName = cppTypeCustomAlloc scoped alloc BT_String
+cppTypeCustomAlloc scoped alloc (BT_List element) = "std::list<" <>> elementTypeName element <<>> ", " <>> allocator scoped alloc element <<> ">"
+cppTypeCustomAlloc scoped alloc (BT_Vector element) = "std::vector<" <>> elementTypeName element <<>> ", " <>> allocator scoped alloc element <<> ">"
+cppTypeCustomAlloc scoped alloc (BT_Set element) = "std::set<" <>> elementTypeName element <<>> comparer element <<>> allocator scoped alloc element <<> ">"
+cppTypeCustomAlloc scoped alloc (BT_Map key value) = "std::map<" <>> elementTypeName key <<>> ", " <>> elementTypeName value <<>> comparer key <<>> pairAllocator scoped alloc key value <<> ">"
+cppTypeCustomAlloc _ _ t = cppType t
 
+cppTypeExpandAliases :: (Type -> TypeNameBuilder) -> Type -> TypeNameBuilder
+cppTypeExpandAliases _ (BT_UserDefined a@Alias {..} args) = aliasTypeName a args
+cppTypeExpandAliases m t = m t
+
 comparer :: Type -> TypeNameBuilder
 comparer t = ", std::less<" <>> elementTypeName t <<> ">, "
 
-allocator :: Builder -> Type -> TypeNameBuilder
-allocator alloc element =
-    "typename " <>> alloc <>> "::rebind<" <>> elementTypeName element <<> ">::other"
+rebindAllocator :: Bool -> Builder -> TypeNameBuilder -> TypeNameBuilder
+rebindAllocator False alloc element = "typename std::allocator_traits<" <>> alloc <>> ">::template rebind_alloc<" <>> element <<> ">"
+rebindAllocator True alloc element = "std::scoped_allocator_adaptor<" <>> rebindAllocator False alloc element <<> " >"
 
-pairAllocator :: Builder -> Type -> Type -> TypeNameBuilder
-pairAllocator alloc key value =
-    "typename " <>> alloc <>> "::rebind<" <>> "std::pair<const " <>> elementTypeName key <<>> ", " <>> elementTypeName value <<> "> >::other"
+allocator :: Bool -> Builder -> Type -> TypeNameBuilder
+allocator scoped alloc element = rebindAllocator scoped alloc $ elementTypeName element
 
+pairAllocator :: Bool -> Builder -> Type -> Type -> TypeNameBuilder
+pairAllocator scoped alloc key value = rebindAllocator scoped alloc $ "std::pair<const " <>> elementTypeName key <<>> ", " <>> elementTypeName value <<> "> "
+
 cppSyntaxFix :: Builder -> Builder
 cppSyntaxFix = fromLazyText . snd . L.foldr fixInvalid (' ', mempty) . toLazyText
   where
@@ -450,4 +521,64 @@
    | otherwise = typeName $ resolveAlias a args
 csTypeAnnotation _ (BT_UserDefined decl args) = declTypeName decl <<>> (angles <$> commaSepTypeNames args)
 csTypeAnnotation m t = m t
+
+
+-- Java type mapping
+javaType :: Type -> TypeNameBuilder
+javaType BT_Int8 = pure "byte"
+javaType BT_Int16 = pure "short"
+javaType BT_Int32 = pure "int"
+javaType BT_Int64 = pure "long"
+javaType BT_UInt8 = pure "byte"
+javaType BT_UInt16 = pure "short"
+javaType BT_UInt32 = pure "int"
+javaType BT_UInt64 = pure "long"
+javaType BT_Float = pure "float"
+javaType BT_Double = pure "double"
+javaType BT_Bool = pure "boolean"
+javaType BT_String = pure "java.lang.String"
+javaType BT_WString = pure "java.lang.String"
+javaType BT_MetaName = pure "java.lang.String"
+javaType BT_MetaFullName = pure "java.lang.String"
+javaType BT_Blob = pure "org.bondlib.Blob"
+javaType (BT_IntTypeArg x) = pureText x
+javaType (BT_Maybe BT_Int8) = pure "org.bondlib.SomethingByte"
+javaType (BT_Maybe BT_Int16) = pure "org.bondlib.SomethingShort"
+javaType (BT_Maybe BT_Int32) = pure "org.bondlib.SomethingInteger"
+javaType (BT_Maybe BT_Int64) = pure "org.bondlib.SomethingLong"
+javaType (BT_Maybe BT_UInt8) = pure "org.bondlib.SomethingByte"
+javaType (BT_Maybe BT_UInt16) = pure "org.bondlib.SomethingShort"
+javaType (BT_Maybe BT_UInt32) = pure "org.bondlib.SomethingInteger"
+javaType (BT_Maybe BT_UInt64) = pure "org.bondlib.SomethingLong"
+javaType (BT_Maybe BT_Float) = pure "org.bondlib.SomethingFloat"
+javaType (BT_Maybe BT_Double) = pure "org.bondlib.SomethingDouble"
+javaType (BT_Maybe BT_Bool) = pure "org.bondlib.SomethingBoolean"
+javaType (BT_UserDefined a@Alias {} args) = javaType (resolveAlias a args)
+javaType (BT_Maybe (BT_UserDefined a@Alias {} args)) = javaType (BT_Maybe (resolveAlias a args))
+javaType (BT_Maybe fieldType) = "org.bondlib.SomethingObject<" <>> javaBoxedType fieldType <<> ">"
+javaType (BT_Nullable elementType) = javaBoxedType elementType
+javaType (BT_List elementType) = "java.util.List<" <>> elementTypeName elementType <<> ">"
+javaType (BT_Vector elementType) = "java.util.List<" <>> elementTypeName elementType <<> ">"
+javaType (BT_Set elementType) = "java.util.Set<" <>> elementTypeName elementType <<> ">"
+javaType (BT_Map keyType valueType) = "java.util.Map<" <>> elementTypeName keyType <<>> ", " <>> elementTypeName valueType <<> ">"
+javaType (BT_TypeParam param) = pureText $ paramName param
+javaType (BT_Bonded structType) = "org.bondlib.Bonded<" <>> javaBoxedType structType <<> ">"
+javaType (BT_UserDefined decl args) =
+    declQualifiedTypeName decl <<>> (angles <$> localWith (const javaBoxedTypeMapping) (commaSepTypeNames args))
+
+-- Java type mapping to a reference type with primitive types boxed
+javaBoxedType :: Type -> TypeNameBuilder
+javaBoxedType BT_Int8 = pure "java.lang.Byte"
+javaBoxedType BT_Int16 = pure "java.lang.Short"
+javaBoxedType BT_Int32 = pure "java.lang.Integer"
+javaBoxedType BT_Int64 = pure "java.lang.Long"
+javaBoxedType BT_UInt8 = pure "java.lang.Byte"
+javaBoxedType BT_UInt16 = pure "java.lang.Short"
+javaBoxedType BT_UInt32 = pure "java.lang.Integer"
+javaBoxedType BT_UInt64 = pure "java.lang.Long"
+javaBoxedType BT_Float = pure "java.lang.Float"
+javaBoxedType BT_Double = pure "java.lang.Double"
+javaBoxedType BT_Bool = pure "java.lang.Boolean"
+javaBoxedType (BT_UserDefined a@Alias {} args) = aliasElementTypeName a args
+javaBoxedType t = javaType t
 
diff --git a/src/Language/Bond/Codegen/Util.hs b/src/Language/Bond/Codegen/Util.hs
--- a/src/Language/Bond/Codegen/Util.hs
+++ b/src/Language/Bond/Codegen/Util.hs
@@ -11,18 +11,24 @@
 Stability   : provisional
 Portability : portable
 
-Helper functions for creating common text structures useful in code generation.
-These functions operate on 'Text' objects.
+Helper functions for creating common structures useful in code generation.
+These functions often operate on 'Text' objects.
 -}
 
 module Language.Bond.Codegen.Util
     ( commonHeader
+    , commaSep
     , newlineSep
     , commaLineSep
     , newlineSepEnd
     , newlineBeginSep
     , doubleLineSep
     , doubleLineSepEnd
+    , uniqueName
+    , uniqueNames
+    , indent
+    , newLine
+    , slashForward
     ) where
 
 import Data.Int (Int64)
@@ -31,7 +37,7 @@
 import Data.Text.Lazy (Text, justifyRight)
 import Text.Shakespeare.Text
 import Paths_bond (version)
-import Data.Version (showVersion) 
+import Data.Version (showVersion)
 import Language.Bond.Util
 
 instance ToText Word16 where
@@ -59,7 +65,11 @@
 
 #{indent n}|]
 
-newlineSep, commaLineSep, newlineSepEnd, newlineBeginSep, doubleLineSep, doubleLineSepEnd 
+-- | Separates elements of a list with a comma.
+commaSep :: (a -> Text) -> [a] -> Text
+commaSep = sepBy ", "
+
+newlineSep, commaLineSep, newlineSepEnd, newlineBeginSep, doubleLineSep, doubleLineSepEnd
     :: Int64 -> (a -> Text) -> [a] -> Text
 
 -- | Separates elements of a list with new lines. Starts new lines at the
@@ -88,13 +98,14 @@
 
 -- | Returns common header for generated files using specified single-line
 -- comment lead character(s) and a file name.
-commonHeader ::  ToText a => a -> a -> Text
-commonHeader c file = [lt|
+commonHeader ::  ToText a => a -> a -> a -> Text
+commonHeader c input output = [lt|
 #{c}------------------------------------------------------------------------------
 #{c} This code was generated by a tool.
 #{c}
 #{c}   Tool : Bond Compiler #{showVersion version}
-#{c}   File : #{file}
+#{c}   Input filename:  #{input}
+#{c}   Output filename: #{output}
 #{c}
 #{c} Changes to this file may cause incorrect behavior and will be lost when
 #{c} the code is regenerated.
@@ -102,3 +113,28 @@
 #{c}------------------------------------------------------------------------------
 |]
 
+-- | Given an intended name and a list of already taken names, returns a
+-- unique name. Assumes that it's legal to append digits to the end of the
+-- intended name.
+uniqueName :: String -> [String] -> String
+uniqueName baseName taken = go baseName (0::Integer)
+  where go name counter
+          | not (name `elem` taken) = name
+          | otherwise = go newName (counter + 1)
+                        where newName = baseName ++ (show counter)
+
+-- | Given a list of names with duplicates and a list of reserved names,
+-- create a list of unique names using the uniqueName function.
+uniqueNames :: [String] -> [String] -> [String]
+uniqueNames names reservedInit = reverse $ go names [] reservedInit
+  where
+    go [] acc _ = acc
+    go (name:remaining) acc reservedAcc = go remaining (newName:acc) (newName:reservedAcc)
+      where
+        newName = uniqueName name reservedAcc
+
+-- | Converts all file path slashes to forward slashes.
+slashForward :: String -> String
+slashForward path = map replace path
+  where replace '\\' = '/'
+        replace c    = c
diff --git a/src/Language/Bond/Lexer.hs b/src/Language/Bond/Lexer.hs
--- a/src/Language/Bond/Lexer.hs
+++ b/src/Language/Bond/Lexer.hs
@@ -34,120 +34,179 @@
     , stringLiteral
     , symbol
     , whiteSpace
+    , Environment(..)
+    , ImportResolver
+    , Symbols(..)
+    , Parser
     ) where
 
-import Data.List
 import Control.Monad.Reader
-import Text.ParserCombinators.Parsec
-import qualified Text.Parsec.Token as P
+import Control.Monad.State.Lazy
+import Data.List
+import Data.Void (Void)
+import Language.Bond.Syntax.Types
+import Text.Megaparsec
+import Text.Megaparsec.Char
+import qualified Text.Megaparsec.Char.Lexer as L
 
-type LanguageDef st env = P.GenLanguageDef String st (ReaderT env IO)
+-- parser state, mutable and global
+data Symbols =
+    Symbols
+    { symbols :: [Declaration]  -- list of structs, enums and aliases declared in the current and all imported files
+    , imports :: [FilePath]     -- list of imported files
+    }
 
-bondIdl :: LanguageDef st env
-bondIdl = P.LanguageDef
-    { P.commentStart    = "/*"
-    , P.commentEnd      = "*/"
-    , P.commentLine     = "//"
-    , P.nestedComments  = True
-    , P.identStart      = letter <|> char '_'
-    , P.identLetter     = alphaNum <|> char '_'
-    , P.opStart         = mzero
-    , P.opLetter        = mzero
-    , P.reservedNames   =
-            [ "blob"
-            , "bond_meta"
-            , "bonded"
-            , "bool"
-            , "class"
-            , "double"
-            , "enum"
-            , "false"
-            , "float"
-            , "import"
-            , "int16"
-            , "int32"
-            , "int64"
-            , "int8"
-            , "list"
-            , "map"
-            , "namespace"
-            , "nullable"
-            , "optional"
-            , "required"
-            , "required_optional"
-            , "Schema"
-            , "sealed"
-            , "service"
-            , "set"
-            , "string"
-            , "struct"
-            , "true"
-            , "uint16"
-            , "uint32"
-            , "uint64"
-            , "uint8"
-            , "using"
-            , "var"
-            , "vector"
-            , "view_of"
-            , "void"
-            , "wstring"
-            ]
-    , P.reservedOpNames = []
-    , P.caseSensitive   = True
+type ImportResolver =
+    FilePath                    -- ^ path of the file containing the <https://microsoft.github.io/bond/manual/compiler.html#import-statements import statement>
+ -> FilePath                    -- ^ (usually relative) path of the imported file
+ -> IO (FilePath, String)       -- ^ the resolver function returns the resolved path of the imported file and its content
+
+-- parser environment, immutable but contextual
+data Environment =
+    Environment
+    { currentNamespaces :: [Namespace]  -- namespace(s) in current context
+    , currentParams :: [TypeParam]      -- type parameter(s) for current type (struct or alias)
+    , currentFile :: FilePath           -- path of the current file
+    , resolveImport :: ImportResolver   -- imports resolver
     }
 
-lexer       = P.makeTokenParser bondIdl
+type Parser a = StateT Symbols (ParsecT Void String (ReaderT Environment IO)) a
 
-angles      = P.angles lexer
-braces      = P.braces lexer
-brackets    = P.brackets lexer
-colon       = P.colon lexer
-comma       = P.comma lexer
-commaSep1   = P.commaSep1 lexer
-decimal     = P.decimal lexer
-identifier  = P.identifier lexer
-integer     = P.integer lexer
-keyword     = P.reserved lexer
-lexeme      = P.lexeme lexer
-natural     = P.natural lexer
-parens      = P.parens lexer
-semi        = P.semi lexer
-semiSep     = P.semiSep lexer
-symbol      = P.symbol lexer
-whiteSpace  = P.whiteSpace lexer
+-- space consumer parser
+sc :: Parser ()
+sc = L.space space1 lineCmnt blockCmnt
+  where
+    lineCmnt  = L.skipLineComment "//"
+    blockCmnt = L.skipBlockComment "/*" "*/"
 
-namespaceLexer = P.makeTokenParser bondIdl { P.reservedNames = delete "Schema" (P.reservedNames bondIdl) }
-namespaceIdentifier  = P.identifier namespaceLexer
+-- consume whitespace after every lexeme
+lexeme :: Parser a -> Parser a
+lexeme = L.lexeme sc
 
-equal       = symbol "="
-semiEnd p   = endBy p semi
-commaEnd p  = endBy p comma
+-- list of reserved words
+rws :: [String]
+rws = [ "blob"
+      , "bond_meta"
+      , "bonded"
+      , "bool"
+      , "class"
+      , "double"
+      , "enum"
+      , "false"
+      , "float"
+      , "import"
+      , "int16"
+      , "int32"
+      , "int64"
+      , "int8"
+      , "list"
+      , "map"
+      , "namespace"
+      , "nullable"
+      , "optional"
+      , "required"
+      , "required_optional"
+      , "Schema"
+      , "sealed"
+      , "service"
+      , "set"
+      , "string"
+      , "struct"
+      , "true"
+      , "uint16"
+      , "uint32"
+      , "uint64"
+      , "uint8"
+      , "using"
+      , "var"
+      , "vector"
+      , "view_of"
+      , "void"
+      , "wstring"
+      ]
+
+angles :: Parser a -> Parser a
+angles = between (symbol "<") (symbol ">")
+
+braces :: Parser a -> Parser a
+braces = between (symbol "{") (symbol "}")
+
+brackets :: Parser a -> Parser a
+brackets = between (symbol "[") (symbol "]")
+
+colon :: Parser String
+colon = symbol ":"
+
+comma :: Parser String
+comma = symbol ","
+
+commaSep1 p = sepBy1 p comma
+
+identifier' :: [String] -> Parser String
+identifier' restricted = (lexeme . try) (p >>= check)
+  where
+    p       = (:) <$> (letterChar <|> char '_') <*> many (alphaNumChar <|> char '_')
+    check x = if x `elem` restricted
+                then fail $ "keyword " ++ show x ++ " cannot be an identifier"
+                else return x
+
+identifier = identifier' rws
+
+decimal :: Parser Integer
+decimal = lexeme L.decimal
+
+integer = L.signed sc natural
+
+keyword :: String -> Parser ()
+keyword w = lexeme (string w *> notFollowedBy (alphaNumChar <|> char '_'))
+
+hexadecimal :: Parser Integer
+hexadecimal = lexeme . try $ char '0' >> char' 'x' >> L.hexadecimal
+
+octal :: Parser Integer
+octal = lexeme . try $ char '0' >> char' 'o' >> L.octal
+
+natural = hexadecimal <|> octal <|> decimal
+
+parens :: Parser a -> Parser a
+parens = between (symbol "(") (symbol ")")
+
+semi :: Parser String
+semi = symbol ";"
+
+semiSep p = sepBy p semi
+
+symbol :: String -> Parser String
+symbol = L.symbol sc
+
+whiteSpace = sc
+
+namespaceIdentifier = identifier' (delete "Schema" rws)
+
+equal = symbol "="
+semiEnd p = endBy p semi
+commaEnd p = endBy p comma
 commaEnd1 p = endBy1 p comma
 
 semiOrComma = semi <|> comma
 
-semiOrCommaSep p     = sepBy p semiOrComma
-semiOrCommaSep1 p    = sepBy1 p semiOrComma
-semiOrCommaEnd p     = endBy p semiOrComma
-semiOrCommaSepEnd p  = sepEndBy p semiOrComma
+semiOrCommaSep p = sepBy p semiOrComma
+semiOrCommaSep1 p = sepBy1 p semiOrComma
+semiOrCommaEnd p = endBy p semiOrComma
+semiOrCommaSepEnd p = sepEndBy p semiOrComma
 semiOrCommaSepEnd1 p = sepEndBy1 p semiOrComma
 
 quote = symbol "\""
 quotes = between quote quote
 
-stringLiteral = P.stringLiteral lexer
+stringLiteral :: Parser String
+stringLiteral = char '"' >> manyTill L.charLiteral (char '"')
 
 unescapedStringLiteral = quotes $ many $ satisfy (/= '"')
 
--- Can't use float from Text.Parsec.Token because it doesn't handle numbers
--- starting with +/- sign.
-float = do
-    s <- sign
-    f <- P.float lexer
-    return $ s f
-  where
-    sign = (char '-' >> return negate)
-       <|> (char '+' >> return id)
-       <|> return id
+float' :: Parser Double
+float' = lexeme L.float
+
+float :: Parser Double
+float = L.signed sc float'
 
diff --git a/src/Language/Bond/Parser.hs b/src/Language/Bond/Parser.hs
--- a/src/Language/Bond/Parser.hs
+++ b/src/Language/Bond/Parser.hs
@@ -21,103 +21,90 @@
     )
     where
 
-import Data.Ord
-import Data.List
+import Control.Applicative hiding (some)
+import Control.Monad.Reader
+import Control.Monad.State.Lazy
 import Data.Function
 import Data.Int
+import Data.List
+import Data.Maybe (fromMaybe)
+import Data.Ord
+import Data.Void (Void)
 import Data.Word
-import Control.Applicative
-import Control.Monad.Reader
-import Prelude
-import Text.Parsec.Pos (initialPos)
-import Text.Parsec hiding (many, optional, (<|>))
 import Language.Bond.Lexer
+import Language.Bond.Syntax.Internal
 import Language.Bond.Syntax.Types
 import Language.Bond.Syntax.Util
-import Language.Bond.Syntax.Internal
-
--- parser state, mutable and global
-data Symbols =
-    Symbols
-    { symbols :: [Declaration]  -- list of structs, enums and aliases declared in the current and all imported files
-    , imports :: [FilePath]     -- list of imported files
-    }
-
-type ImportResolver =
-    FilePath                    -- ^ path of the file containing the <https://microsoft.github.io/bond/manual/compiler.html#import-statements import statement>
- -> FilePath                    -- ^ (usually relative) path of the imported file
- -> IO (FilePath, String)       -- ^ the resolver function returns the resolved path of the imported file and its content
-
--- parser environment, immutable but contextual
-data Environment =
-    Environment
-    { currentNamespaces :: [Namespace]  -- namespace(s) in current context
-    , currentParams :: [TypeParam]      -- type parameter(s) for current type (struct or alias)
-    , currentFile :: FilePath           -- path of the current file
-    , resolveImport :: ImportResolver   -- imports resolver
-    }
-
-type Parser a = ParsecT String Symbols (ReaderT Environment IO) a
+import Prelude
+import Text.Megaparsec hiding (many, optional, (<|>))
+import Text.Megaparsec.Char (char)
 
 -- | Parses content of a schema definition file.
 parseBond ::
-    SourceName                          -- ^ source name, used only for error messages
+    String                              -- ^ source name, used only for error messages
  -> String                              -- ^ content of a schema file to parse
  -> FilePath                            -- ^ path of the file being parsed, used to resolve relative import paths
  -> ImportResolver                      -- ^ function to resolve and load imported files
- -> IO (Either ParseError Bond)         -- ^ function returns 'Bond' which represents the parsed abstract syntax tree 
+ -> IO (Either (ParseErrorBundle String Void) Bond)         -- ^ function returns 'Bond' which represents the parsed abstract syntax tree
                                         --   or 'ParserError' if parsing failed
-parseBond s c f r = runReaderT (runParserT bond (Symbols [] []) s c) (Environment [] [] f r)
+parseBond s c f r = runReaderT (runParserT (evalStateT bond (Symbols [] [])) s c) (Environment [] [] f r)
 
 -- parser for .bond files
 bond :: Parser Bond
 bond = do
     whiteSpace
     imports <- many import_
-    namespaces <- many1 namespace
+    namespaces <- some namespace
     local (with namespaces) $ Bond imports namespaces <$> many declaration <* eof
   where
     with namespaces e = e { currentNamespaces = namespaces }
 
 import_ :: Parser Import
 import_ = do
-    i <- Import <$ keyword "import" <*> unescapedStringLiteral <?> "import statement"
+    i <- Import <$ keyword "import" <*> unescapedStringLiteral <* optional semi <?> "import statement"
     src <- getInput
-    pos <- getPosition
+    pos <- getOffset
     processImport i
     setInput src
-    setPosition pos
+    setOffset pos
     return i
 
 processImport :: Import -> Parser()
 processImport (Import file) = do
     Environment { currentFile = currentFile, resolveImport = resolveImport } <- ask
     (path, content) <- liftIO $ resolveImport currentFile file
-    Symbols { imports = imports } <- getState
+    Symbols { imports = imports } <- get
     if path `elem` imports then return () else do
-            modifyState (\u -> u { imports = path:imports } )
+            modify (\u -> u { imports = path:imports } )
             setInput content
-            setPosition $ initialPos path
+            setSourcePos $ initialPos path
             void $ local (\e -> e { currentFile = path }) bond
 
 -- parser for struct, enum or type alias declaration/definition
 declaration :: Parser Declaration
 declaration = do
+    -- When adding a new Declaration parser, order matters in the following command.
+    -- Parsers must fail to consume ANY token for the next parser to be able to successfully work
+    -- unless the parser is encapsulated in a try statement. For more info on try and <|> see:
+    -- https://hackage.haskell.org/package/megaparsec-6.2.0/docs/Text-Megaparsec.html#v:try
     decl <- try forward
-        <|> try struct
-        <|> try view
-        <|> try enum
-        <|> try alias
-        <|> try service
+        <|> alias
+        <|> (attributes >>= \a -> (service a <|> enum a <|> structDeclaration a))
     updateSymbols decl <?> "declaration"
     return decl
 
+structDeclaration :: [Attribute] -> Parser Declaration
+structDeclaration attr = do
+    name <- keyword "struct" *> identifier <?> "struct or struct view definition"
+    decl <- view attr name <|> struct attr name
+    return decl
+
 updateSymbols :: Declaration -> Parser ()
 updateSymbols decl = do
-    (previous, symbols) <- partition (duplicateDeclaration decl) <$> symbols <$> getState
+    (previous, symbols) <- partition (duplicateDeclaration decl) <$> symbols <$> get
     case reconcile previous decl of
         (False, _) -> fail $ "The " ++ showPretty decl ++ " has been previously defined as " ++ showPretty (head previous)
-        (True, f) -> modifyState (f symbols)
+        (True, f) -> modify (f symbols)
   where
     reconcile [x@Forward {}] y@Struct {} = (paramsMatch x y, add y)
     reconcile [x@Forward {}] y@Forward {} = (paramsMatch x y, const id)
@@ -141,7 +128,7 @@
   where
     doFind = do
         namespaces <- asks currentNamespaces
-        Symbols { symbols = symbols } <- getState
+        Symbols { symbols = symbols } <- get
         case find (declMatching namespaces name) symbols of
             Just decl -> return decl
             Nothing -> fail $ "Unknown symbol: " ++ showQualifiedName name
@@ -171,9 +158,9 @@
 namespace = Namespace <$ keyword "namespace" <*> language <*> qualifiedName <* optional semi <?> "namespace declaration"
   where
     language = optional (keyword "cpp" *> pure Cpp
+                     <|> keyword "csharp" *> pure Cs
                      <|> keyword "cs" *> pure Cs
-                     <|> keyword "java" *> pure Java
-                     <|> keyword "csharp" *> pure Cs)
+                     <|> keyword "java" *> pure Java)
 
 -- identifier optionally qualified with namespace
 qualifiedName :: Parser QualifiedName
@@ -189,7 +176,7 @@
 -- type alias
 alias :: Parser Declaration
 alias = do
-    name <- keyword "using" *> identifier <?> "alias definition"
+    name <- try (keyword "using") *> identifier <?> "alias definition"
     params <- parameters
     namespaces <- asks currentNamespaces
     local (with params) $ Alias namespaces name params <$ equal <*> type_ <* semi
@@ -209,11 +196,9 @@
     attribute = brackets (Attribute <$> qualifiedName <*> parens stringLiteral <?> "attribute")
 
 -- struct view parser
-view :: Parser Declaration
-view = do
-    attr <- attributes
-    name <- keyword "struct" *> identifier <?> "struct view definition"
-    decl <- keyword "view_of" *> qualifiedName >>= findStruct
+view :: [Attribute] -> String -> Parser Declaration
+view attr name = do
+    decl <- try (keyword "view_of") *> qualifiedName >>= findStruct <?> "struct view definition"
     fields <- braces $ semiOrCommaSepEnd1 identifier
     namespaces <- asks currentNamespaces
     Struct namespaces attr name (declParams decl) (structBase decl) (viewFields decl fields) <$ optional semi
@@ -222,30 +207,26 @@
     viewFields _           _      = error "view/viewFields: impossible happened."
 
 -- struct definition parser
-struct :: Parser Declaration
-struct = do
-    attr <- attributes
-    name <- keyword "struct" *> identifier <?> "struct definition"
+struct :: [Attribute] -> String -> Parser Declaration
+struct attr name = do
     params <- parameters
     namespaces <- asks currentNamespaces
     updateSymbols $ Forward namespaces name params
     local (with params) $ Struct namespaces attr name params <$> base <*> fields <* optional semi
   where
     base = optional (colon *> userType <?> "base struct")
-    fields = unique $ braces $ manySortedBy (comparing fieldOrdinal) (field <* semi)
+    fields = sortFields $ unique $ braces $ many (field <* semi)
     with params e = e { currentParams = params }
+    sortFields p = do
+        fields' <- p
+        return $ sortBy (comparing fieldOrdinal) fields'
     unique p = do
         fields' <- p
         case findDuplicatesBy fieldOrdinal fields' ++ findDuplicatesBy fieldName fields' of
             [] -> return fields'
             Field {..}:_ -> fail $ "Duplicate definition of the field with ordinal " ++ show fieldOrdinal ++
                 " and name " ++ show fieldName
-      where
-        findDuplicatesBy accessor xs = deleteFirstsBy ((==) `on` accessor) xs (nubBy ((==) `on` accessor) xs)
 
-manySortedBy :: (a -> a -> Ordering) -> ParsecT s u m a -> ParsecT s u m [a]
-manySortedBy = manyAccum . insertBy
-
 -- field definition parser
 field :: Parser Field
 field = do
@@ -263,8 +244,8 @@
                 else fail "Field ordinal must be within the range 0-65535"
     modifier = option Optional
                     (keyword "optional" *> pure Optional
-                 <|> keyword "required" *> pure Required
-                 <|> keyword "required_optional" *> pure RequiredOptional)
+                 <|> keyword "required_optional" *> pure RequiredOptional
+                 <|> keyword "required" *> pure Required)
     default_ = equal *>
                     (keyword "true" *> pure (DefaultBool True)
                  <|> keyword "false" *> pure (DefaultBool False)
@@ -282,41 +263,11 @@
                                         then Right $ Field a o m t n d
                                         else Left "Invalid default value for field"
 
--- default type validator (type checking, out-of-range, enforce default type)
-validDefaultType :: Type -> Maybe Default -> Bool
-validDefaultType (BT_UserDefined a@Alias {} args) d = validDefaultType (resolveAlias a args) d
-validDefaultType _ Nothing = True
-validDefaultType bondType (Just defaultValue) = validDefaultType' bondType defaultValue
-  where validDefaultType' :: Type -> Default -> Bool
-        validDefaultType' BT_Int8    (DefaultInteger i) = isInBounds i (0::Int8)
-        validDefaultType' BT_Int16   (DefaultInteger i) = isInBounds i (0::Int16)
-        validDefaultType' BT_Int32   (DefaultInteger i) = isInBounds i (0::Int32)
-        validDefaultType' BT_Int64   (DefaultInteger i) = isInBounds i (0::Int64)
-        validDefaultType' BT_UInt8   (DefaultInteger i) = isInBounds i (0::Word8)
-        validDefaultType' BT_UInt16  (DefaultInteger i) = isInBounds i (0::Word16)
-        validDefaultType' BT_UInt32  (DefaultInteger i) = isInBounds i (0::Word32)
-        validDefaultType' BT_UInt64  (DefaultInteger i) = isInBounds i (0::Word64)
-        validDefaultType' BT_Float   (DefaultFloat _)   = True
-        validDefaultType' BT_Float   (DefaultInteger _) = True
-        validDefaultType' BT_Double  (DefaultFloat _)   = True
-        validDefaultType' BT_Double  (DefaultInteger _) = True
-        validDefaultType' BT_Bool    (DefaultBool _)    = True
-        validDefaultType' BT_String  (DefaultString _)  = True
-        validDefaultType' BT_WString (DefaultString _)  = True
-        validDefaultType' (BT_UserDefined Enum {} _) (DefaultEnum _) = True
-        validDefaultType' (BT_TypeParam {}) _           = True
-        validDefaultType' _ _                           = False
-
--- checks whether an Integer is within the bounds of some other Integral and Bounded type.
--- The value of the second paramater is never used: only its type is used.
-isInBounds :: forall a. (Integral a, Bounded a) => Integer -> a -> Bool
-isInBounds value _ = value >= (toInteger (minBound :: a)) && value <= (toInteger (maxBound :: a))
-
 -- enum definition parser
-enum :: Parser Declaration
-enum = Enum <$> asks currentNamespaces <*> attributes <*> name <*> consts <* optional semi <?> "enum definition"
+enum :: [Attribute] -> Parser Declaration
+enum attr = Enum <$> asks currentNamespaces <*> pure attr <*> name <*> consts <* optional semi <?> "enum definition"
   where
-    name = keyword "enum" *> (identifier <?> "enum identifier")
+    name = try (keyword "enum") *> identifier <?> "enum identifier"
     consts = braces (semiOrCommaSepEnd1 constant <?> "enum constant")
     constant = Constant <$> identifier <*> optional value
     value = equal *> (fromIntegral <$> integer)
@@ -338,7 +289,6 @@
     <|> keyword "string" *> pure BT_String
     <|> keyword "bool" *> pure BT_Bool
 
-
 -- containers parser
 complexType :: Parser Type
 complexType =
@@ -348,13 +298,11 @@
     <|> keyword "nullable" *> angles (BT_Nullable <$> type_)
     <|> keyword "set" *> angles (BT_Set <$> keyType)
     <|> keyword "map" *> angles (BT_Map <$> keyType <* comma <*> type_)
-    <|> keyword "bonded" *> angles (BT_Bonded <$> userStruct)
+    <|> keyword "bonded" *> angles (BT_Bonded <$> userStructRef)
   where
     keyType = try (basicType <|> checkUserType isValidKeyType) <?> "scalar, string or enum"
-    userStruct = try (checkUserType isStruct) <?> "user defined struct"
     isValidKeyType t = isScalar t || isString t
 
-
 -- parser for user defined type (struct, enum, alias or type parameter)
 userType :: Parser Type
 userType = do
@@ -364,6 +312,15 @@
         Right (Service {..}, _) -> fail $ "Unexpected service " ++ declName ++ ". Expected struct, enum or alias."
         Right (decl, args) -> return $ BT_UserDefined decl args
 
+-- parser for service type
+serviceType :: Parser Type
+serviceType = do
+    symbol_ <- userSymbol
+    case symbol_ of
+        Right (decl@Service{}, args) -> return $ BT_UserDefined decl args
+        Right (decl, _) -> fail $ "Unexpected type " ++ (declName decl) ++ ". Expected a service."
+        Left param -> fail $ "Unexpected type parameter " ++ (paramName param) ++ ". Expected a service."
+
 userSymbol :: Parser (Either TypeParam (Declaration, [Type]))
 userSymbol = do
     name <- qualifiedName
@@ -390,9 +347,10 @@
     isParam _      = const False
 
 
+
 -- type parser
 type_ :: Parser Type
-type_ = basicType <|> complexType <|> userType
+type_ = (try basicType) <|> (try complexType) <|> (try userType)
 
 -- field type parser
 ftype :: Parser Type
@@ -401,42 +359,118 @@
     <|> type_
 
 -- service definition parser
-service :: Parser Declaration
-service = do
-    attr <- attributes
-    name <- keyword "service" *> identifier <?> "service definition"
+service :: [Attribute] -> Parser Declaration
+service attr = do
+    name <- try (keyword "service") *> identifier <?> "service definition"
     params <- parameters
     namespaces <- asks currentNamespaces
-    local (with params) $ Service namespaces attr name params <$> methods <* optional semi
+    local (with params) $ Service namespaces attr name params <$> base <*> methods <* optional semi
   where
+    base = optional (colon *> serviceType <?> "base service")
     with params e = e { currentParams = params }
-    methods = braces $ semiEnd (try event <|> try function)
+    methods = checkUniqueMethodNames $ braces $ semiEnd method
+    checkUniqueMethodNames p = do
+        methods' <- p
+        case findDuplicatesBy methodName methods' of
+            [] -> return methods'
+            Function {..}:_ -> fail $ "Duplicate definition of the function with name " ++ show methodName
+            Event {..}:_ -> fail $ "Duplicate definition of the event with name " ++ show methodName
 
-function :: Parser Method
-function = Function <$> attributes <*> payload <*> identifier <*> input
+method :: Parser Method
+method = attributes >>= \a -> ((lookAhead (keyword "nothing") *> event a) <|> function a)
 
-event :: Parser Method
-event = Event <$> attributes <* keyword "nothing" <*> identifier <*> input
+function :: [Attribute] -> Parser Method
+function attr = Function attr <$> functionResultType <*> identifier <*> input
+  where functionResultType = methodTypeVoid  <|> methodResultTypeStreaming <|> methodTypeUnary
 
-input :: Parser (Maybe Type)
-input = do
-  pld <- parens $ optional payload
-  case pld of
-      Nothing -> pure Nothing
-      Just m -> return m
+event :: [Attribute] -> Parser Method
+event attr = do
+  _ <- keyword "nothing"
+  methodName <- identifier
+  methodInput <- input
+  case methodInput of
+    (Streaming _) -> fail $ "Incompatible nothing return and streaming input in method " ++ show methodName
+    _ -> return (Event attr methodName methodInput)
 
-payload :: Parser (Maybe Type)
-payload = void_ <|> liftM Just userStruct
-  where
-    void_ = keyword "void" *> pure Nothing
-    userStruct = try (checkUserType isStruct) <?> "user defined struct"
+input :: Parser MethodType
+input = parens methodInputType
+  where methodInputType = (fromMaybe Void) <$> optional (methodTypeVoid <|> methodInputTypeStreaming <|> methodTypeUnary)
 
+methodTypeVoid :: Parser MethodType
+methodTypeVoid = try (keyword "void" *> pure Void) <?> "void method type"
+
+-- Whether the method type is streaming or is unary can be determined based on
+-- context, but the context is different for result and input types.
+--
+-- For result types, the keyword stream followed by a struct name AND THEN
+-- an identifier indicates a streaming type. Two identifiers are required to
+-- distinguish between the unary method "stream stream()" and the streaming
+-- method "stream stream stream()".
+--
+-- For input types, simply the keyword stream followed by a struct name is
+-- enough to distinguish between the unary "foo(stream)" and the streaming
+-- "foo(stream stream)".
+methodResultTypeStreaming :: Parser MethodType
+methodResultTypeStreaming = try (do
+                                    _ <- keyword "stream"
+                                    resultType <- userStructRef
+                                    _ <- lookAhead identifier
+                                    return (Streaming resultType)) <?> "streaming method type"
+
+methodInputTypeStreaming :: Parser MethodType
+methodInputTypeStreaming = try (Streaming <$ keyword "stream" <*> userStructRef) <?> "streaming method type"
+
+methodTypeUnary :: Parser MethodType
+methodTypeUnary = (Unary <$> userStructRef) <?> "unary method type"
+
+-- helper methods
+
 checkUserType :: (Type -> Bool) -> Parser Type
 checkUserType check = do
     t <- userType
-    if (valid t) then return t else unexpected "type"
+    if (valid t) then return t else fail "unexpected type"
   where
     valid t = case t of
         BT_TypeParam _ -> True
         _ -> check t
 
+userStructRef :: Parser Type
+userStructRef = try (checkUserType isStruct) <?> "user defined struct reference"
+
+findDuplicatesBy :: (Eq b) => (a -> b) -> [a] -> [a]
+findDuplicatesBy accessor xs = deleteFirstsBy ((==) `on` accessor) xs (nubBy ((==) `on` accessor) xs)
+
+-- default type validator (type checking, out-of-range, enforce default type)
+validDefaultType :: Type -> Maybe Default -> Bool
+validDefaultType (BT_UserDefined a@Alias {} args) d = validDefaultType (resolveAlias a args) d
+validDefaultType _ Nothing = True
+validDefaultType bondType (Just defaultValue) = validDefaultType' bondType defaultValue
+  where validDefaultType' :: Type -> Default -> Bool
+        validDefaultType' BT_Int8    (DefaultInteger i) = isInBounds i (0::Int8)
+        validDefaultType' BT_Int16   (DefaultInteger i) = isInBounds i (0::Int16)
+        validDefaultType' BT_Int32   (DefaultInteger i) = isInBounds i (0::Int32)
+        validDefaultType' BT_Int64   (DefaultInteger i) = isInBounds i (0::Int64)
+        validDefaultType' BT_UInt8   (DefaultInteger i) = isInBounds i (0::Word8)
+        validDefaultType' BT_UInt16  (DefaultInteger i) = isInBounds i (0::Word16)
+        validDefaultType' BT_UInt32  (DefaultInteger i) = isInBounds i (0::Word32)
+        validDefaultType' BT_UInt64  (DefaultInteger i) = isInBounds i (0::Word64)
+        validDefaultType' BT_Float   (DefaultFloat _)   = True
+        validDefaultType' BT_Float   (DefaultInteger _) = True
+        validDefaultType' BT_Double  (DefaultFloat _)   = True
+        validDefaultType' BT_Double  (DefaultInteger _) = True
+        validDefaultType' BT_Bool    (DefaultBool _)    = True
+        validDefaultType' BT_String  (DefaultString _)  = True
+        validDefaultType' BT_WString (DefaultString _)  = True
+        validDefaultType' (BT_UserDefined Enum {} _) (DefaultEnum _) = True
+        validDefaultType' (BT_TypeParam {}) _           = True
+        validDefaultType' _ _                           = False
+
+-- checks whether an Integer is within the bounds of some other Integral and Bounded type.
+-- The value of the second parameter is never used: only its type is used.
+isInBounds :: forall a. (Integral a, Bounded a) => Integer -> a -> Bool
+isInBounds value _ = value >= (toInteger (minBound :: a)) && value <= (toInteger (maxBound :: a))
+
+-- sets source position
+setSourcePos ::  MonadParsec e s m => SourcePos -> m ()
+setSourcePos src = updateParserState setPos
+    where setPos (State s o (PosState i o' _ t l)) =  State s o (PosState i o' src t l)
diff --git a/src/Language/Bond/Syntax/Internal.hs b/src/Language/Bond/Syntax/Internal.hs
--- a/src/Language/Bond/Syntax/Internal.hs
+++ b/src/Language/Bond/Syntax/Internal.hs
@@ -10,6 +10,7 @@
     , takeNamespace
     , isBaseField
     , metaField
+    , baseFields
     ) where
 
 import Data.Monoid
@@ -51,3 +52,7 @@
 isBaseField :: String -> Maybe Type -> Bool
 isBaseField name = getAny . optional (foldMapFields (Any.(name==).fieldName))
 
+-- If a Declaration is a Struct then return the Fields of its Parent
+baseFields :: Declaration -> Maybe [Field]
+baseFields Struct{..} = foldMapFields return <$> structBase
+baseFields _ = Nothing
diff --git a/src/Language/Bond/Syntax/JSON.hs b/src/Language/Bond/Syntax/JSON.hs
--- a/src/Language/Bond/Syntax/JSON.hs
+++ b/src/Language/Bond/Syntax/JSON.hs
@@ -1,7 +1,7 @@
 -- Copyright (c) Microsoft. All rights reserved.
 -- Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
-{-# LANGUAGE OverloadedStrings, RecordWildCards, TemplateHaskell #-}
+{-# LANGUAGE OverloadedStrings, QuasiQuotes, RecordWildCards, ScopedTypeVariables, TemplateHaskell #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 {-|
@@ -18,12 +18,16 @@
     )
     where
 
+import Control.Applicative
 import Data.Aeson
-import Data.Aeson.Types
 import Data.Aeson.TH
-import Control.Applicative
+import Data.Aeson.Types
+import Data.HashMap.Strict (member)
+import Data.Text.Lazy (unpack)
+import Language.Bond.Syntax.Types hiding (MethodType(..))
+import qualified Language.Bond.Syntax.Types as BST (MethodType(..))
 import Prelude
-import Language.Bond.Syntax.Types
+import Text.Shakespeare.Text (lt)
 
 -- $aeson
 --
@@ -137,7 +141,7 @@
     toJSON (BT_IntTypeArg n) = object
         [ "type" .= String "constant"
         , "value" .= n
-        ]
+       ]
     toJSON (BT_TypeParam p) = object
         [ "type" .= String "parameter"
         , "value" .= p
@@ -211,7 +215,7 @@
         [ "fieldAttributes" .= fieldAttributes f
         , "fieldOrdinal" .= fieldOrdinal f
         , "fieldModifier" .= fieldModifier f
-        , "fieldType" .= fieldType f 
+        , "fieldType" .= fieldType f
         , "fieldName" .= fieldName f
         , "fieldDefault" .= fieldDefault f
         ]
@@ -260,6 +264,100 @@
         , "declarations" .= bondDeclarations
         ]
 
+instance ToJSON BST.MethodType where
+    toJSON BST.Void = Null
+    toJSON (BST.Unary t) = toJSON t
+    toJSON (BST.Streaming t) = toJSON t
+
+data MethodStreamingTag = Unary | Client | Server | Duplex deriving Show
+$(deriveJSON defaultOptions ''MethodStreamingTag)
+
+methodStreamingTag :: BST.MethodType -> BST.MethodType -> MethodStreamingTag
+methodStreamingTag input result = case (input, result) of
+  (BST.Streaming _, BST.Streaming _) -> Duplex
+  (BST.Streaming _, _) -> Client
+  (_, BST.Streaming _) -> Server
+  _ -> Unary
+
+instance ToJSON Method where
+    toJSON Event {..} = object
+        [ "tag" .= String "Event"
+        , "methodName" .= methodName
+        , "methodAttributes" .= methodAttributes
+        , "methodInput" .= methodInput
+        ]
+    toJSON Function {..} = object
+        [ "tag" .= String "Function"
+        , "methodName" .= methodName
+        , "methodAttributes" .= methodAttributes
+        , "methodResult" .= methodResult
+        , "methodInput" .= methodInput
+        , "methodStreaming" .= (methodStreamingTag methodInput methodResult)
+        ]
+
+instance FromJSON Method where
+  parseJSON = withObject "Method" (\o -> do
+    tag <- o .: "tag"
+    methodName :: String <- o .:? "methodName" .!= "<unknown>"
+    case tag of
+      (String "Event") -> modifyFailure ((unpack [lt|Parsing event '#{show methodName}' failed: |]) ++) (parseEvent o)
+      (String "Function") -> modifyFailure ((unpack [lt|Parsing function '#{show methodName}' failed: |]) ++) (parseFunction o)
+      _ -> modifyFailure (const $ unpack [lt|Unexpected tag '#{show tag}' when parsing method '#{show methodName}'. Expecting "Event" or "Function".|]) empty)
+    where
+      parseEvent :: Object -> Parser Method
+      parseEvent o =
+        Event <$>
+          o .:? "methodAttributes" .!= [] <*>
+          o .: "methodName" <*>
+          methodInput
+        <* ensureNoMethodStreaming
+        where ensureNoMethodStreaming = if member "methodStreaming" o
+                                          then fail "Encountered Event with \"methodStreaming\" member. Events cannot have this member."
+                                          else pure ()
+              methodInput = maybe BST.Void BST.Unary <$> (o .:? "methodInput")
+
+      parseFunction :: Object -> Parser Method
+      parseFunction o =
+          Function <$>
+            o .:? "methodAttributes" .!= [] <*>
+            methodResult <*>
+            o .: "methodName" <*>
+            methodInput
+        where
+          streamingTag :: Parser MethodStreamingTag
+          streamingTag = o .:? "methodStreaming"  .!= Unary
+
+          methodInput :: Parser BST.MethodType
+          methodInput = do
+            i <- o .:? "methodInput"
+            st <- streamingTag
+            case (i, st) of
+              (Nothing, Unary) -> pure $ BST.Void
+              (Nothing, Client) -> fail $ invalidNothingComboMsg "input" Client
+              (Nothing, Server) -> pure $ BST.Void
+              (Nothing, Duplex) -> fail $ invalidNothingComboMsg "input" Duplex
+              (Just t, Unary) -> pure $ BST.Unary t
+              (Just t, Client) -> pure $ BST.Streaming t
+              (Just t, Server) -> pure $ BST.Unary t
+              (Just t, Duplex) -> pure $ BST.Streaming t
+
+          methodResult :: Parser BST.MethodType
+          methodResult = do
+            r <- o .:? "methodResult"
+            st <- streamingTag
+            case (r, st) of
+              (Nothing, Unary) -> pure $ BST.Void
+              (Nothing, Client) -> pure $ BST.Void
+              (Nothing, Server) -> fail $ invalidNothingComboMsg "result" Server
+              (Nothing, Duplex) -> fail $ invalidNothingComboMsg "result" Duplex
+              (Just t, Unary) -> pure $ BST.Unary t
+              (Just t, Client) -> pure $ BST.Unary t
+              (Just t, Server) -> pure $ BST.Streaming t
+              (Just t, Duplex) -> pure $ BST.Streaming t
+
+          invalidNothingComboMsg :: String -> MethodStreamingTag -> String
+          invalidNothingComboMsg dir streaming = unpack [lt|Method marked as #{show streaming}, but has void #{dir}|]
+
 $(deriveJSON defaultOptions ''Modifier)
 $(deriveJSON defaultOptions ''Attribute)
 $(deriveJSON defaultOptions ''Constant)
@@ -267,4 +365,3 @@
 $(deriveJSON defaultOptions ''Declaration)
 $(deriveJSON defaultOptions ''Import)
 $(deriveJSON defaultOptions ''Language)
-$(deriveJSON defaultOptions ''Method)
diff --git a/src/Language/Bond/Syntax/SchemaDef.hs b/src/Language/Bond/Syntax/SchemaDef.hs
--- a/src/Language/Bond/Syntax/SchemaDef.hs
+++ b/src/Language/Bond/Syntax/SchemaDef.hs
@@ -200,12 +200,7 @@
         resolve (BT_UserDefined a@Alias{} args) = resolve $ resolveAlias a args
         resolve t = t
     -- resolve value of an enum constant
-    resolveEnum Enum{..} n = fromIntegral . snd . fromJust $ find ((n ==) . fst) $ nameValues 0 enumConstants
-      where
-        -- fill in values for constants w/o explicitly specified value
-        nameValues _ [] = []
-        nameValues _ ((Constant name (Just value)):xs) = (name, value) : nameValues (value + 1) xs
-        nameValues next ((Constant name Nothing):xs)   = (name, next) : nameValues (next + 1) xs
+    resolveEnum Enum{..} n = fromIntegral . snd . fromJust $ find ((n ==) . fst) $ reifyEnumValues enumConstants
     resolveEnum _ _ = error "makeSchemaDef.resolveEnum: not a enum"
 
 $(deriveToJSON defaultOptions {omitNothingFields = True} ''SchemaDef)
diff --git a/src/Language/Bond/Syntax/Types.hs b/src/Language/Bond/Syntax/Types.hs
--- a/src/Language/Bond/Syntax/Types.hs
+++ b/src/Language/Bond/Syntax/Types.hs
@@ -30,7 +30,9 @@
     , Type(..)
     , TypeParam(..)
     , Constraint(..)
-      -- ** Comm
+      -- ** Services
+    , MethodType(..)
+    , methodTypeToMaybe
     , Method(..)
       -- ** Metadata
     , Attribute(..)
@@ -121,22 +123,39 @@
         }
     deriving (Eq, Show)
 
+data MethodType = Void | Unary Type | Streaming Type
+  deriving (Eq, Show)
+
 -- | Method of a service
 data Method =
     Function
         { methodAttributes :: [Attribute]   -- zero or more attributes
-        , methodResult :: Maybe Type        -- method result
+        , methodResult :: MethodType        -- method result
         , methodName :: String              -- method name
-        , methodInput :: Maybe Type         -- method parameter
+        , methodInput :: MethodType         -- method parameter
         }
     |
     Event
         { methodAttributes :: [Attribute]   -- zero or more attributes
         , methodName :: String              -- method name
-        , methodInput :: Maybe Type         -- method parameter
+        , methodInput :: MethodType         -- method parameter
         }
     deriving (Eq, Show)
 
+-- | Converts a MethodType into a Maybe Type to ease the transition from the
+-- current definition of Method (which uses MethodType for input/results)
+-- and the previous definition which used Maybe Type.
+--
+-- This is intended to be used by codegen that doesn't yet support streaming
+-- (e.g., C++ and Comm). Once that code has been updated to understand
+-- streaming, this function will be removed.
+--
+-- Raises an error if given a Streaming type.
+methodTypeToMaybe :: MethodType -> Maybe Type
+methodTypeToMaybe Void = Nothing
+methodTypeToMaybe (Unary t) = Just t
+methodTypeToMaybe (Streaming t) = error ("Unable to handle streaming " ++ (show t) ++ " in this codegen mode.")
+
 -- | Bond schema declaration
 data Declaration =
     Struct
@@ -173,6 +192,7 @@
         , declAttributes :: [Attribute]     -- zero or more attributes
         , declName :: String                -- service name
         , declParams :: [TypeParam]         -- type parameters for generic service
+        , serviceBase :: Maybe Type         -- optional base service
         , serviceMethods :: [Method]        -- zero or more methods
         }                                   -- ^ <https://microsoft.github.io/bond/manual/compiler.html#service-definition service definition>
     deriving (Eq, Show)
diff --git a/src/Language/Bond/Syntax/Util.hs b/src/Language/Bond/Syntax/Util.hs
--- a/src/Language/Bond/Syntax/Util.hs
+++ b/src/Language/Bond/Syntax/Util.hs
@@ -36,6 +36,7 @@
     , foldMapType
       -- * Helper functions
     , resolveAlias
+    , reifyEnumValues
     ) where
 
 import Data.Maybe
@@ -231,3 +232,12 @@
     paramsArgs = zip declParams args
 resolveAlias _ _ = error "resolveAlias: impossible happened."
 
+
+
+-- | Fill in values for constants w/o explicitly specified value
+reifyEnumValues :: [Constant] -> [(String, Int)]
+reifyEnumValues constants = nameValues 0 constants
+  where
+    nameValues _ [] = []
+    nameValues _ ((Constant name (Just value)):xs) = (name, value) : nameValues (value + 1) xs
+    nameValues next ((Constant name Nothing):xs)   = (name, next) : nameValues (next + 1) xs
diff --git a/src/Language/Bond/Util.hs b/src/Language/Bond/Util.hs
--- a/src/Language/Bond/Util.hs
+++ b/src/Language/Bond/Util.hs
@@ -20,6 +20,7 @@
     , sepEndBy
     , sepBeginBy
     , optional
+    , ifThenElse
     , angles
     , brackets
     , braces
@@ -69,6 +70,11 @@
 -- to the value inside 'Just' and returns the result.
 optional :: (Monoid m) => (a -> m) -> Maybe a -> m
 optional = maybe mempty
+
+-- if-then-else as a function
+ifThenElse :: Bool -> a -> a -> a
+ifThenElse True thenCondition _ = thenCondition
+ifThenElse False _ elseCondition = elseCondition
 
 -- | If the 3rd argument is not 'mempty' the function wraps it between the
 -- first and second argument using 'mappend', otherwise it return 'mempty'.
diff --git a/tests/Main.hs b/tests/Main.hs
deleted file mode 100644
--- a/tests/Main.hs
+++ /dev/null
@@ -1,146 +0,0 @@
--- Copyright (c) Microsoft. All rights reserved.
--- Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-import Test.Tasty
-import Test.Tasty.QuickCheck
-import Test.Tasty.HUnit (testCase)
-import Tests.Syntax
-import Tests.Codegen
-
-tests :: TestTree
-tests = testGroup "Compiler tests"
-    [ testGroup "AST"
-        [ localOption (QuickCheckMaxSize 6) $
-            testProperty "roundtrip" roundtripAST
-        , testGroup "Compare .bond and .json"
-            [ testCase "attributes" $ compareAST "attributes"
-            , testCase "basic types" $ compareAST "basic_types"
-            , testCase "bond_meta types" $ compareAST "bond_meta"
-            , testCase "complex types" $ compareAST "complex_types"
-            , testCase "default values" $ compareAST "defaults"
-            , testCase "empty" $ compareAST "empty"
-            , testCase "field modifiers" $ compareAST "field_modifiers"
-            , testCase "generics" $ compareAST "generics"
-            , testCase "inheritance" $ compareAST "inheritance"
-            , testCase "type aliases" $ compareAST "aliases"
-            , testCase "documentation example" $ compareAST "example"
-            , testCase "simple service syntax" $ compareAST "service"
-            , testCase "service attributes" $ compareAST "service_attributes"
-            , testCase "generic service" $ compareAST "generic_service"
-            , testCase "documentation example" $ compareAST "example"
-            ]
-        ]
-    , testGroup "SchemaDef"
-        [ verifySchemaDef "attributes" "Foo"
-        , verifySchemaDef "basic_types" "BasicTypes"
-        , verifySchemaDef "defaults" "Foo"
-        , verifySchemaDef "field_modifiers" "Foo"
-        , verifySchemaDef "inheritance" "Foo"
-        , verifySchemaDef "alias_key" "foo"
-        , verifySchemaDef "maybe_blob" "Foo"
-        , verifySchemaDef "nullable_alias" "foo"
-        , verifySchemaDef "schemadef" "AliasBase"
-        , verifySchemaDef "schemadef" "EnumDefault"
-        , verifySchemaDef "schemadef" "StringTree"
-        , verifySchemaDef "example" "SomeStruct"
-        ]
-    , testGroup "Types"
-        [ testCase "type alias resolution" aliasResolution
-        ]
-    , testGroup "Codegen Failures (Expect to see errors below check for OK or FAIL)"
-        [ testCase "Struct default value nothing" $ failBadSyntax "Should fail when default value of a struct field is 'nothing'" "struct_nothing"
-        , testCase "Enum no default value" $ failBadSyntax "Should fail when an enum field has no default value" "enum_no_default"
-        , testCase "Alias default value" $ failBadSyntax "Should fail when underlying default value is of the wrong type" "aliases_default"
-        , testCase "Out of range" $ failBadSyntax "Should fail, out of range for int16" "int_out_of_range"
-        ]
-    , testGroup "Codegen"
-        [ testGroup "C++"
-            [ verifyCppCodegen "attributes"
-            , verifyCppCodegen "basic_types"
-            , verifyCppCodegen "bond_meta"
-            , verifyCppCodegen "complex_types"
-            , verifyCppCodegen "defaults"
-            , verifyCppCodegen "empty"
-            , verifyCppCodegen "field_modifiers"
-            , verifyCppCodegen "generics"
-            , verifyCppCodegen "inheritance"
-            , verifyCppCodegen "aliases"
-            , verifyCppCodegen "alias_key"
-            , verifyCppCodegen "maybe_blob"
-            , verifyCodegen
-                [ "c++"
-                , "--allocator=arena"
-                ]
-                "alias_with_allocator"
-            , verifyCodegen
-                [ "c++"
-                , "--allocator=arena"
-                , "--using=List=my::list<{0}, arena>"
-                , "--using=Vector=my::vector<{0}, arena>"
-                , "--using=Set=my::set<{0}, arena>"
-                , "--using=Map=my::map<{0}, {1}, arena>"
-                , "--using=String=my::string<arena>"
-                ]
-                "custom_alias_with_allocator"
-            , verifyCodegen
-                [ "c++"
-                , "--allocator=arena"
-                , "--using=List=my::list<{0}>"
-                , "--using=Vector=my::vector<{0}>"
-                , "--using=Set=my::set<{0}>"
-                , "--using=Map=my::map<{0}, {1}>"
-                , "--using=String=my::string"
-                ]
-                "custom_alias_without_allocator"
-            , verifyApplyCodegen
-                [ "c++"
-                , "--apply-attribute=DllExport"
-                ]
-                "basic_types"
-            ]
-            , testGroup "Comm"
-                [ verifyCppCommCodegen
-                    [ "c++"
-                    ]
-                    "service"
-                , verifyCppCommCodegen
-                    [ "c++"
-                    ]
-                    "generic_service"
-                , verifyCppCommCodegen
-                    [ "c++"
-                    ]
-                    "service_attributes"
-                ]
-    , testGroup "C#"
-            [ verifyCsCodegen "attributes"
-            , verifyCsCodegen "basic_types"
-            , verifyCsCodegen "bond_meta"
-            , verifyCsCodegen "complex_types"
-            , verifyCsCodegen "defaults"
-            , verifyCsCodegen "empty"
-            , verifyCsCodegen "field_modifiers"
-            , verifyCsCodegen "generics"
-            , verifyCsCodegen "inheritance"
-            , verifyCsCodegen "aliases"
-            , verifyCodegen
-                [ "c#"
-                , "--using=time=System.DateTime"
-                ]
-                "nullable_alias"
-            , testGroup "Comm"
-                [ verifyCsCommCodegen
-                    [ "c#"
-                    ]
-                    "service"
-                , verifyCsCommCodegen
-                    [ "c#"
-                    ]
-                    "generic_service"
-                ]
-            ]
-        ]
-    ]
-
-main :: IO ()
-main = defaultMain tests
diff --git a/tests/TestMain.hs b/tests/TestMain.hs
new file mode 100644
--- /dev/null
+++ b/tests/TestMain.hs
@@ -0,0 +1,220 @@
+-- Copyright (c) Microsoft. All rights reserved.
+-- Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+import Test.Tasty
+import Test.Tasty.QuickCheck
+import Test.Tasty.HUnit (testCase)
+import Tests.Syntax
+import Tests.Syntax.JSON(methodParsingTests)
+import Tests.Codegen
+import Tests.Codegen.Util(utilTestGroup)
+
+tests :: TestTree
+tests = testGroup "Compiler tests"
+    [ testGroup "AST"
+        [ localOption (QuickCheckMaxSize 6) $
+            testProperty "roundtrip" roundtripAST
+        , testGroup "Compare .bond and .json"
+            [ testCase "attributes" $ compareAST "attributes"
+            , testCase "basic types" $ compareAST "basic_types"
+            , testCase "bond_meta types" $ compareAST "bond_meta"
+            , testCase "complex types" $ compareAST "complex_types"
+            , testCase "default values" $ compareAST "defaults"
+            , testCase "empty" $ compareAST "empty"
+            , testCase "field modifiers" $ compareAST "field_modifiers"
+            , testCase "generics" $ compareAST "generics"
+            , testCase "inheritance" $ compareAST "inheritance"
+            , testCase "type aliases" $ compareAST "aliases"
+            , testCase "documentation example" $ compareAST "example"
+            , testCase "simple service syntax" $ compareAST "service"
+            , testCase "service attributes" $ compareAST "service_attributes"
+            , testCase "generic service" $ compareAST "generic_service"
+            , testCase "streaming service" $ compareAST "streaming"
+            , testCase "documentation example" $ compareAST "example"
+            , testCase "service inheritance" $ compareAST "service_inheritance"
+            ]
+        , methodParsingTests
+        ]
+    , testGroup "SchemaDef"
+        [ verifySchemaDef "attributes" "Foo"
+        , verifySchemaDef "basic_types" "BasicTypes"
+        , verifySchemaDef "defaults" "Foo"
+        , verifySchemaDef "field_modifiers" "Foo"
+        , verifySchemaDef "inheritance" "Foo"
+        , verifySchemaDef "alias_key" "foo"
+        , verifySchemaDef "maybe_blob" "Foo"
+        , verifySchemaDef "nullable_alias" "foo"
+        , verifySchemaDef "schemadef" "AliasBase"
+        , verifySchemaDef "schemadef" "EnumDefault"
+        , verifySchemaDef "schemadef" "StringTree"
+        , verifySchemaDef "example" "SomeStruct"
+        ]
+    , testGroup "Types"
+        [ testCase "type alias resolution" aliasResolution
+        ]
+    , testGroup "Codegen Failures (Expect to see errors below check for OK or FAIL)"
+        [ testCase "Struct default value nothing" $ failBadSyntax "Should fail when default value of a struct field is 'nothing'" "struct_nothing"
+        , testCase "Enum no default value" $ failBadSyntax "Should fail when an enum field has no default value" "enum_no_default"
+        , testCase "Alias default value" $ failBadSyntax "Should fail when underlying default value is of the wrong type" "aliases_default"
+        , testCase "Out of range" $ failBadSyntax "Should fail, out of range for int16" "int_out_of_range"
+        , testCase "Duplicate method definition in service" $ failBadSyntax "Should fail, method name should be unique" "duplicate_service_method"
+        , testCase "Invalid service base: struct" $ failBadSyntax "Should fail, struct can't be used as service base" "service_invalid_base_struct"
+        , testCase "Invalid service base: type param" $ failBadSyntax "Should fail, type param can't be used as service base" "service_invalid_base_type_param"
+        ]
+    , testGroup "Codegen"
+        [ utilTestGroup,
+          testGroup "C++"
+            [ verifyCppCodegen "attributes"
+            , verifyCppCodegen "basic_types"
+            , verifyCppCodegen "bond_meta"
+            , verifyCppCodegen "complex_types"
+            , verifyCppCodegen "defaults"
+            , verifyCppCodegen "empty"
+            , verifyCppCodegen "field_modifiers"
+            , verifyCppCodegen "generics"
+            , verifyCppCodegen "inheritance"
+            , verifyCppCodegen "aliases"
+            , verifyCppCodegen "alias_key"
+            , verifyCppCodegen "maybe_blob"
+            , verifyCppCodegen "metadata_edge_cases"
+            , verifyCodegen
+                [ "c++"
+                , "--enum-header"
+                ]
+                "with_enum_header"
+            , verifyCodegen
+                 [ "c++"
+                 , "--import-dir=tests/schema/imports"
+                 ]
+                 "import"
+            , verifyCodegen
+                [ "c++"
+                , "--allocator=arena"
+                ]
+                "alias_with_allocator"
+            , verifyCodegen
+                [ "c++"
+                , "--allocator=arena"
+                , "--using=List=my::list<{0}, arena>"
+                , "--using=Vector=my::vector<{0}, arena>"
+                , "--using=Set=my::set<{0}, arena>"
+                , "--using=Map=my::map<{0}, {1}, arena>"
+                , "--using=String=my::string<arena>"
+                ]
+                "custom_alias_with_allocator"
+            , verifyCodegen
+                [ "c++"
+                , "--allocator=arena"
+                , "--using=List=my::list<{0}>"
+                , "--using=Vector=my::vector<{0}>"
+                , "--using=Set=my::set<{0}>"
+                , "--using=Map=my::map<{0}, {1}>"
+                , "--using=String=my::string"
+                ]
+                "custom_alias_without_allocator"
+           , testGroup "Apply"
+                [ verifyApplyCodegen
+                    [ "c++"
+                    , "--apply-attribute=DllExport"
+                    ]
+                    "basic_types"
+                ]
+           , testGroup "Exports"
+                [ verifyExportsCodegen
+                    [ "c++"
+                    , "--export-attribute=DllExport"
+                    ]
+                    "with_enum_header"
+                ]
+            , verifyCodegen
+                [ "c++"
+                , "--namespace=tests=nsmapped"
+                ]
+                "basic_types_nsmapped"
+            ]
+        , testGroup "C#"
+            [ verifyCsCodegen "attributes"
+            , verifyCsCodegen "basic_types"
+            , verifyCsCodegen "bond_meta"
+            , verifyCsCodegen "complex_types"
+            , verifyCsCodegen "defaults"
+            , verifyCsCodegen "empty"
+            , verifyCsCodegen "field_modifiers"
+            , verifyCsCodegen "generics"
+            , verifyCsCodegen "inheritance"
+            , verifyCsCodegen "aliases"
+            , verifyCsCodegen "complex_inheritance"
+            , verifyCodegen
+                [ "c#"
+                , "--using=ImmutableArray=System.Collections.Immutable.ImmutableArray<{0}>"
+                , "--using=ImmutableList=System.Collections.Immutable.ImmutableList<{0}>"
+                , "--using=ImmutableHashSet=System.Collections.Immutable.ImmutableHashSet<{0}>"
+                , "--using=ImmutableSortedSet=System.Collections.Immutable.ImmutableSortedSet<{0}>"
+                , "--using=ImmutableDictionary=System.Collections.Immutable.ImmutableDictionary<{0},{1}>"
+                , "--using=ImmutableSortedDictionary=System.Collections.Immutable.ImmutableSortedDictionary<{0},{1}>"
+                ]
+                "immutable_collections"
+            , verifyCodegenVariation
+                [ "c#"
+                , "--preview-constructor-parameters"
+                , "--readonly-properties"
+                ]
+                "complex_inheritance"
+                "constructor-parameters"
+            , verifyCodegenVariation
+                [ "c#"
+                , "--preview-constructor-parameters"
+                , "--fields"
+                ]
+                "complex_inheritance"
+                "constructor-parameters_fields"
+            , verifyCodegen
+                [ "c#"
+                , "--using=time=System.DateTime"
+                ]
+                "nullable_alias"
+            , verifyCodegen
+                [ "c#"
+                , "--namespace=tests=nsmapped"
+                ]
+                "basic_types_nsmapped"
+            , verifyCodegen
+                 [ "c#"
+                 , "--import-dir=tests/schema/imports"
+                 ]
+                 "import"
+            , verifyCodegenVariation
+                [ "c#"
+                , "--preview-constructor-parameters"
+                , "--readonly-properties"
+                ]
+                "empty_struct"
+                "constructor-parameters"
+            ]
+        , testGroup "Java"
+            [ verifyJavaCodegen "attributes"
+            , verifyJavaCodegen "basic_types"
+            , verifyJavaCodegen "bond_meta"
+            , verifyJavaCodegen "complex_types"
+            , verifyJavaCodegen "defaults"
+            , verifyJavaCodegen "empty"
+            , verifyJavaCodegen "field_modifiers"
+            , verifyJavaCodegen "generics"
+            , verifyJavaCodegen "inheritance"
+            , verifyJavaCodegen "aliases"
+            , verifyCodegen
+                [ "java"
+                , "--namespace=tests=nsmapped"
+                ]
+                "basic_types_nsmapped"
+            , verifyCodegen
+                 [ "java"
+                 , "--import-dir=tests/schema/imports"
+                 ]
+                 "import"
+            ]
+        ]
+    ]
+
+main :: IO ()
+main = defaultMain tests
diff --git a/tests/Tests/Codegen.hs b/tests/Tests/Codegen.hs
--- a/tests/Tests/Codegen.hs
+++ b/tests/Tests/Codegen.hs
@@ -6,11 +6,12 @@
 
 module Tests.Codegen
     ( verifyCodegen
+    , verifyCodegenVariation
     , verifyCppCodegen
-    , verifyCppCommCodegen
     , verifyApplyCodegen
+    , verifyExportsCodegen
     , verifyCsCodegen
-    , verifyCsCommCodegen
+    , verifyJavaCodegen
     ) where
 
 import System.FilePath
@@ -20,13 +21,14 @@
 import Prelude
 import Data.Algorithm.DiffContext
 import Data.Text.Lazy (Text, unpack)
+import qualified Data.Text.Lazy as LT
 import qualified Data.ByteString.Char8 as BS
 import Text.PrettyPrint (render, text)
 import Test.Tasty
 import Test.Tasty.Golden.Advanced
 import Language.Bond.Codegen.Templates
 import Language.Bond.Codegen.TypeMapping
-import Language.Bond.Syntax.Types (Bond(..), Import, Declaration)
+import Language.Bond.Syntax.Types (Bond(..), Import, Declaration(..))
 import Options
 import IO
 
@@ -38,11 +40,19 @@
 verifyCsCodegen :: FilePath -> TestTree
 verifyCsCodegen = verifyCodegen ["c#"]
 
+verifyJavaCodegen :: FilePath -> TestTree
+verifyJavaCodegen = verifyCodegen ["java"]
+
 verifyCodegen :: [String] -> FilePath -> TestTree
 verifyCodegen args baseName =
     testGroup baseName $
-        verifyFiles (processOptions args) baseName
+        verifyFiles (processOptions args) baseName ""
 
+verifyCodegenVariation :: [String] -> FilePath -> FilePath -> TestTree
+verifyCodegenVariation args baseName variation =
+    testGroup baseName $
+        verifyFiles (processOptions args) baseName variation
+
 verifyApplyCodegen :: [String] -> FilePath -> TestTree
 verifyApplyCodegen args baseName =
     testGroup baseName $
@@ -50,46 +60,33 @@
   where
     options = processOptions args
     templates =
-        [ apply_h protocols (apply_attribute options)
+        [ apply_h protocols (export_attribute options)
         , apply_cpp protocols
         ]
     protocols =
-        [ Protocol "bond::CompactBinaryReader<bond::InputBuffer>"
-                   "bond::CompactBinaryWriter<bond::OutputBuffer>"
-        , Protocol "bond::FastBinaryReader<bond::InputBuffer>"
-                   "bond::FastBinaryWriter<bond::OutputBuffer>"
-        , Protocol "bond::SimpleBinaryReader<bond::InputBuffer>"
-                   "bond::SimpleBinaryWriter<bond::OutputBuffer>"
+        [ ProtocolReader "bond::CompactBinaryReader<bond::InputBuffer>"
+        , ProtocolWriter "bond::CompactBinaryWriter<bond::OutputBuffer>"
+        , ProtocolWriter "bond::CompactBinaryWriter<bond::OutputCounter>"
+        , ProtocolReader "bond::FastBinaryReader<bond::InputBuffer>"
+        , ProtocolWriter "bond::FastBinaryWriter<bond::OutputBuffer>"
+        , ProtocolReader "bond::SimpleBinaryReader<bond::InputBuffer>"
+        , ProtocolWriter "bond::SimpleBinaryWriter<bond::OutputBuffer>"
         ]
 
-verifyCppCommCodegen :: [String] -> FilePath -> TestTree
-verifyCppCommCodegen args baseName =
-    testGroup baseName $
-        map (verifyFile (processOptions args) baseName cppTypeMapping "")
-            [ comm_h
-            , types_cpp
-            , types_comm_cpp
-            ]
-
-verifyCsCommCodegen :: [String] -> FilePath -> TestTree
-verifyCsCommCodegen args baseName =
+verifyExportsCodegen :: [String] -> FilePath -> TestTree
+verifyExportsCodegen args baseName =
     testGroup baseName $
-        map (verifyFile (processOptions args) baseName csTypeMapping "")
-            [ comm_interface_cs
-            , comm_proxy_cs
-            , comm_service_cs
-            , types_cs Class (fieldMapping (processOptions args))
-            ]
+        map (verifyFile options baseName (cppExpandAliases (type_aliases_enabled options) cppTypeMapping) "exports") (templates options)
   where
-    fieldMapping Cs {..} = if readonly_properties
-        then ReadOnlyProperties
-        else if fields
-             then PublicFields
-             else Properties
+    options = processOptions args
+    templates Cpp {..} =
+        [ reflection_h export_attribute
+        , types_h export_attribute header enum_header allocator alloc_ctors_enabled type_aliases_enabled scoped_alloc_enabled
+        ]
 
-verifyFiles :: Options -> FilePath -> [TestTree]
-verifyFiles options baseName =
-    map (verify (typeMapping options) "") (templates options)
+verifyFiles :: Options -> FilePath -> FilePath -> [TestTree]
+verifyFiles options baseName variation =
+    map (verify (typeMapping options) variation) (templates options)
     <>
     extra options
   where
@@ -99,27 +96,51 @@
         else if fields
              then PublicFields
              else Properties
-    typeMapping Cpp {..} = maybe cppTypeMapping cppCustomAllocTypeMapping allocator
+    constructorOptions Cs {..} = if constructor_parameters
+        then ConstructorParameters
+        else DefaultWithProtectedBase
+    typeMapping Cpp {..} = cppExpandAliases type_aliases_enabled $ maybe cppTypeMapping (cppCustomAllocTypeMapping scoped_alloc_enabled) allocator
     typeMapping Cs {} = csTypeMapping
+    typeMapping Java {} = javaTypeMapping
     templates Cpp {..} =
-        [ reflection_h
+        [ (reflection_h export_attribute)
         , types_cpp
-        , types_comm_cpp
-        , types_h header enum_header allocator
-        ]
+        , types_h export_attribute header enum_header allocator alloc_ctors_enabled type_aliases_enabled scoped_alloc_enabled
+        ] <>
+        [ enum_h | enum_header]
     templates Cs {..} =
-        [ types_cs Class $ fieldMapping options
+        [ types_cs Class (fieldMapping options) (constructorOptions options)
         ]
+    templates Java {} =
+        [ javaCatTemplate
+        ]
     extra Cs {} =
         [ testGroup "collection interfaces" $
-            map (verify csCollectionInterfacesTypeMapping "collection-interfaces") (templates options)
+            map (verify csCollectionInterfacesTypeMapping (variation </> "collection-interfaces")) (templates options)
         ]
     extra Cpp {..} =
         [ testGroup "custom allocator" $
-            map (verify (cppCustomAllocTypeMapping "arena") "allocator")
+            map (verify (cppExpandAliasesTypeMapping $ cppCustomAllocTypeMapping False "arena") (variation </> "allocator"))
                 (templates $ options { allocator = Just "arena" })
             | isNothing allocator
+        ] ++
+        [ testGroup "constructors with allocator argument" $
+            map (verify (cppExpandAliasesTypeMapping $ cppCustomAllocTypeMapping False "arena") (variation </> "alloc_ctors"))
+                (templates $ options { allocator = Just "arena", alloc_ctors_enabled = True })
+            | isNothing allocator
+        ] ++
+        [ testGroup "type aliases" $
+            map (verify (cppCustomAllocTypeMapping False "arena") (variation </> "type_aliases"))
+                (templates $ options { allocator = Just "arena", type_aliases_enabled = True })
+        ] ++
+        [ testGroup "scoped allocator" $
+            map (verify (cppExpandAliasesTypeMapping $ cppCustomAllocTypeMapping True "arena") (variation </> "scoped_allocator"))
+                (templates $ options { allocator = Just "arena", scoped_alloc_enabled = True })
+            | isNothing allocator
         ]
+    extra Java {} =
+        [
+        ]
 
 verifyFile :: Options -> FilePath -> TypeMapping -> FilePath -> Template -> TestTree
 verifyFile options baseName typeMapping subfolder template =
@@ -132,7 +153,7 @@
     codegen = do
         aliasMapping <- parseAliasMappings $ using options
         namespaceMapping <- parseNamespaceMappings $ namespace options
-        (Bond imports namespaces declarations) <- parseBondFile [] $ "tests" </> "schema" </> baseName <.> "bond"
+        (Bond imports namespaces declarations) <- parseBondFile (import_dir options) $ "tests" </> "schema" </> baseName <.> "bond"
         let mappingContext = MappingContext typeMapping aliasMapping namespaceMapping namespaces
         let (_, code) = template mappingContext baseName imports declarations
         return $ BS.pack $ unpack code
@@ -142,3 +163,19 @@
                             (text "test output")
                             (text . BS.unpack)
                             (getContextDiff 3 (BS.lines x) (BS.lines y))
+
+javaCatTemplate :: MappingContext -> String -> [Import] -> [Declaration] -> (String, Text)
+javaCatTemplate mappingContext _ imports declarations =
+  (suffix, LT.concat $ mapMaybe codegenDecl declarations)
+    where
+      suffix = "_concatenated.java"
+      codegenDecl declaration =
+        case declaration of
+          Struct {} -> Just $ class_java mappingContext imports declaration
+          Enum {}   -> Just $ enum_java mappingContext declaration
+          _         -> Nothing
+
+cppExpandAliases :: Bool -> TypeMapping -> TypeMapping
+cppExpandAliases type_aliases_enabled = if type_aliases_enabled
+    then id
+    else cppExpandAliasesTypeMapping
diff --git a/tests/Tests/Codegen/Util.hs b/tests/Tests/Codegen/Util.hs
new file mode 100644
--- /dev/null
+++ b/tests/Tests/Codegen/Util.hs
@@ -0,0 +1,20 @@
+-- Copyright (c) Microsoft. All rights reserved.
+-- Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
+module Tests.Codegen.Util
+    (
+      utilTestGroup
+    ) where
+
+import Language.Bond.Codegen.Util(uniqueName)
+import Test.Tasty
+import Test.Tasty.QuickCheck
+
+utilTestGroup = testGroup "Codegen Utils"
+  [ testGroup "uniqueName" [ testProperty "unique when taken" prop_collisionReturnsNotSame,
+                             testProperty "given when not taken" prop_noCollisionReturnsSame]]
+
+prop_collisionReturnsNotSame xs = not (null xs) ==> uniqueName (head xs) xs /= head xs
+prop_noCollisionReturnsSame xs = not ("some" `elem` xs) ==> uniqueName "some" xs == "some"
diff --git a/tests/Tests/Syntax.hs b/tests/Tests/Syntax.hs
--- a/tests/Tests/Syntax.hs
+++ b/tests/Tests/Syntax.hs
@@ -16,8 +16,8 @@
 import Data.Maybe
 import Data.List
 import Data.Aeson (encode, decode)
-import Data.Aeson.Encode.Pretty (Config(..), encodePretty')
-import Data.DeriveTH
+import Data.Aeson.Encode.Pretty (Config(..), NumberFormat(..), Indent(..), encodePretty')
+import Test.QuickCheck.TH.Generators
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as BL
 import System.FilePath
@@ -30,24 +30,78 @@
 import Language.Bond.Syntax.SchemaDef
 import IO
 
-derive makeArbitrary ''Attribute
-derive makeArbitrary ''Bond
-derive makeArbitrary ''Constant
-derive makeArbitrary ''Constraint
-derive makeArbitrary ''Declaration
-derive makeArbitrary ''Default
-derive makeArbitrary ''Field
-derive makeArbitrary ''Import
-derive makeArbitrary ''Language
-derive makeArbitrary ''Modifier
-derive makeArbitrary ''Namespace
-derive makeArbitrary ''Type
-derive makeArbitrary ''TypeParam
-derive makeArbitrary ''Method
+makeArbitrary ''Attribute
+makeArbitrary ''Constant
+makeArbitrary ''Constraint
+makeArbitrary ''Default
+makeArbitrary ''Field
+makeArbitrary ''Declaration
+makeArbitrary ''Import
+makeArbitrary ''Language
+makeArbitrary ''Modifier
+makeArbitrary ''Namespace
+makeArbitrary ''Type
+makeArbitrary ''TypeParam
+makeArbitrary ''MethodType
+makeArbitrary ''Bond
 
-roundtripAST :: Bond -> Bool
-roundtripAST x = (decode . encode) x == Just x
 
+instance Arbitrary Attribute where
+  arbitrary = arbitraryAttribute
+
+instance Arbitrary Field where
+  arbitrary = arbitraryField
+
+instance Arbitrary Constant where
+  arbitrary = arbitraryConstant
+
+instance Arbitrary Default where
+  arbitrary = arbitraryDefault
+
+instance Arbitrary Declaration where
+  arbitrary = arbitraryDeclaration
+
+instance Arbitrary Import where
+  arbitrary = arbitraryImport
+
+instance Arbitrary Constraint where
+  arbitrary = arbitraryConstraint
+
+instance Arbitrary Language where
+  arbitrary = arbitraryLanguage
+
+instance Arbitrary Modifier where
+  arbitrary = arbitraryModifier
+
+
+instance Arbitrary Namespace where
+  arbitrary = arbitraryNamespace
+
+instance Arbitrary TypeParam where
+  arbitrary = arbitraryTypeParam
+
+instance Arbitrary Type where
+  arbitrary = arbitraryType
+
+instance Arbitrary MethodType where
+  arbitrary = arbitraryMethodType
+
+instance Arbitrary Bond where
+  arbitrary = arbitraryBond
+
+
+instance Arbitrary Method where
+  arbitrary = oneof
+    [ Function <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
+    , Event <$> arbitrary <*> arbitrary <*> eventInput]
+    where
+      -- events cannot have streaming input, so we need to customize the
+      -- arbitrary input to omit Streaming
+      eventInput = oneof [return Void,  Unary <$> arbitrary]
+
+roundtripAST :: Bond -> Property
+roundtripAST x = (decode . encode) x === Just x
+
 assertException :: String -> IO a -> Assertion
 assertException errMsg action = do
     e <- try action
@@ -116,15 +170,17 @@
         (Bond _ _ declarations) <- parseBondFile [] $ "tests" </> "schema" </> baseName <.> "bond"
         let schema = fromJust $ find ((schemaName ==) . declName) declarations
         return $
-            -- some versions aeson encode angle brackets
             BL.fromStrict $
+            -- aeson-pretty-print prints anything above 1e19 in scientific notation
+            replace "1.8446744073709551615e19" "18446744073709551615" $
+            -- some versions aeson encode angle brackets
             replace "\\u003c" "<" $
             replace "\\u003e" ">" $
             BL.toStrict $ prettyEncode $ makeSchemaDef $ BT_UserDefined schema []
       where
-        prettyEncode = encodePretty' (Config indentSpaces compare)
+        prettyEncode = encodePretty' (Config indentSpaces compare Generic False)
           where
-            indentSpaces = 2
+            indentSpaces = Spaces 2
         replace s r bs = if B.null t then h else
             B.append h (B.append r $ replace s r (B.drop (B.length s) t))
           where
diff --git a/tests/Tests/Syntax/JSON.hs b/tests/Tests/Syntax/JSON.hs
new file mode 100644
--- /dev/null
+++ b/tests/Tests/Syntax/JSON.hs
@@ -0,0 +1,118 @@
+-- Copyright (c) Microsoft. All rights reserved.
+-- Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}
+
+module Tests.Syntax.JSON
+    ( methodParsingTests
+    ) where
+
+import Data.Aeson (FromJSON, ToJSON, eitherDecode)
+import Data.Aeson.Encode.Pretty (Config(..),NumberFormat(..), Indent(..), encodePretty')
+import Data.ByteString.Lazy (ByteString)
+import Data.Maybe ()
+import Data.Text.Lazy as LT
+import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)
+import Language.Bond.Syntax.JSON ()
+import Language.Bond.Syntax.Types (Declaration(..), Field(..), Method(..), MethodType(..), Modifier(..), Namespace(..), Type(..))
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (Assertion, (@=?), assertFailure, testCase)
+import Text.Shakespeare.Text (lt)
+
+methodParsingTests :: TestTree
+methodParsingTests = testGroup "Method JSON AST Parsing"
+  [ testCase "function without streaming tag: assumed Unary" funcWithoutStreamingTag_assumedUnary
+  , testCase "void function(AnyType) unary parses" $ assertJsonDecode (voidFunc Unary) (voidFuncAst "Unary")
+  , testCase "void function(AnyType) streaming Client parses" $ assertJsonDecode (voidFunc Streaming) (voidFuncAst "Client")
+  , testCase "void function(AnyType) streaming Server fails parsing" $ assertJsonDecodeFails (voidFuncAst "Server") methodDecode
+  , testCase "void function(AnyType) streaming Duplex fails parsing" $ assertJsonDecodeFails (voidFuncAst "Duplex") methodDecode
+  , testCase "nothing event(AnyType) with any methodStreaming fails parsing" $ assertJsonDecodeFails eventWithStreamingTag methodDecode ]
+
+funcWithoutStreamingTag_assumedUnary :: Assertion
+funcWithoutStreamingTag_assumedUnary = assertJsonDecode expected ast
+  where
+    expected = Function
+      { methodAttributes = []
+      , methodResult = Unary anyType
+      , methodName = "anyMethodName"
+      , methodInput = Unary anyType }
+    ast = [lt|{
+"tag": "Function",
+"methodName": "anyMethodName",
+"methodInput": #{anyTypeAst},
+"methodResult": #{anyTypeAst}
+}
+|]
+
+-- | Makes a 'Function' that returns void and has the given input type.
+voidFunc :: (Type -> MethodType) -> Method
+voidFunc streamingType = Function
+      { methodAttributes = []
+      , methodResult = Void
+      , methodName = "anyMethodName"
+      , methodInput = (streamingType anyType) }
+
+-- | Makes the JSON AST for a function that returns void with the given
+-- "methodStreaming" value.
+voidFuncAst :: String -> LT.Text
+voidFuncAst streamingTag = [lt|{
+"tag": "Function",
+"methodName": "anyMethodName",
+"methodInput": #{anyTypeAst},
+"methodStreaming": "#{streamingTag}"
+}
+|]
+
+-- | JSON AST of an event that (erroneously) includes a streaming tag.
+eventWithStreamingTag :: Text
+eventWithStreamingTag = [lt|{
+"tag": "Event",
+"methodName": "anyMethodName",
+"methodInput": #{anyTypeAst},
+"methodStreaming": "Unary"
+}
+|]
+
+-- | JSON AST decoder function for the 'Method' type
+methodDecode :: ByteString -> Either String Method
+methodDecode = eitherDecode
+
+-- | A placeholder user-defined type
+anyType :: Type
+anyType = BT_UserDefined
+             (Struct
+               { declNamespaces = [Namespace { nsLanguage = Nothing, nsName = ["any"] }]
+               , declAttributes = []
+               , declName = "anyTypeName"
+               , declParams = []
+               , structBase = Nothing
+               , structFields = [Field { fieldAttributes = [], fieldOrdinal = 0, fieldModifier = Optional, fieldType = BT_Int16, fieldName = "anyField", fieldDefault = Nothing }] })
+             []
+
+-- | The JSON AST representation of 'anyType'
+anyTypeAst :: LT.Text
+anyTypeAst = encodeText anyType
+
+-- | Helper method that JSON encodes to lazy text
+encodeText :: ToJSON a => a -> LT.Text
+encodeText o = decodeUtf8 (encodePretty' config o)
+  where config = (Config (Spaces 2)  compare Generic False)
+
+-- | Asserts that the given JSON decodes into the expected value
+assertJsonDecode :: (Eq a, FromJSON a, Show a) =>
+  a          -- ^ The expected value
+  -> LT.Text -- ^ the JSON to decode
+  -> Assertion
+assertJsonDecode expected json = case eitherDecode (encodeUtf8 json) of
+  Left parseError -> assertFailure ("JSON parse error: " ++ parseError ++ "\nInput JSON:\n" ++ (LT.unpack json))
+  Right actual -> expected @=? actual
+
+-- | Asserts that attempting to decode the provided 'json' with the provided
+-- 'decode' function fails.
+assertJsonDecodeFails :: Show a =>
+  LT.Text                            -- ^ the JSON to decode
+  -> (ByteString -> Either String a) -- ^ the decode function to run. Usually 'eitherDecode' for a specific type
+  -> Assertion
+assertJsonDecodeFails json decode = case decode (encodeUtf8 json) of
+  Left _ -> return ()
+  Right o -> assertFailure ("Expected JSON parsing to fail, but got '" ++ show o ++ "' instead.")
