diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Changelog
 
+## [0.1.0.0] - 2022-05-03
+
+### Changed
+* Generalise type of `matchChoiceCodec` to allow for two different input types.
+* Add disjoint versions of `matchChoiceCodec` and `matchChoicesCodec`.
+* Functions `enumCodec`, `stringConstCodec`, and `shownBoundedEnumCodec` now produce disjoint codecs.
+
 ## [0.0.1.1] - 2022-04-26
 
 ### Added
diff --git a/autodocodec.cabal b/autodocodec.cabal
--- a/autodocodec.cabal
+++ b/autodocodec.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           autodocodec
-version:        0.0.1.1
+version:        0.1.0.0
 synopsis:       Self-documenting encoder and decoder
 homepage:       https://github.com/NorfairKing/autodocodec#readme
 bug-reports:    https://github.com/NorfairKing/autodocodec/issues
diff --git a/src/Autodocodec.hs b/src/Autodocodec.hs
--- a/src/Autodocodec.hs
+++ b/src/Autodocodec.hs
@@ -104,7 +104,11 @@
 
     -- *** Choice
     matchChoiceCodec,
+    disjointMatchChoiceCodec,
+    matchChoiceCodecAs,
     matchChoicesCodec,
+    disjointMatchChoicesCodec,
+    matchChoicesCodecAs,
 
     -- *** Adding documentation to a codec
     (<?>),
diff --git a/src/Autodocodec/Codec.hs b/src/Autodocodec/Codec.hs
--- a/src/Autodocodec/Codec.hs
+++ b/src/Autodocodec/Codec.hs
@@ -431,14 +431,28 @@
   Codec context newInput newOutput
 dimapCodec f g = bimapCodec (Right . f) g
 
--- | Forward-compatible version of 'PureCodec'
+-- | Produce a value without parsing any part of an 'Object'.
 --
+-- This function exists to implement @Applicative (ObjectCodec input)@.
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'PureCodec'.
+--
 -- > pureCodec = PureCodec
 pureCodec :: output -> ObjectCodec input output
 pureCodec = PureCodec
 
--- | Forward-compatible version of 'ApCodec'
+-- | Sequentially apply two codecs that parse part of an 'Object'.
 --
+-- This function exists to implement @Applicative (ObjectCodec input)@.
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'ApCodec'.
+--
 -- > apCodec = ApCodec
 apCodec :: ObjectCodec input (output -> newOutput) -> ObjectCodec input output -> ObjectCodec input newOutput
 apCodec = ApCodec
@@ -447,8 +461,10 @@
   pure = pureCodec
   (<*>) = apCodec
 
--- | Also allow @null@ during decoding of a 'Maybe' value.
+-- | Maybe codec
 --
+-- This can be used to also allow @null@ during decoding of a 'Maybe' value.
+--
 -- During decoding, also accept a @null@ value as 'Nothing'.
 -- During encoding, encode as usual.
 --
@@ -473,9 +489,10 @@
       Nothing -> Left ()
       Just r -> Right r
 
--- | Forward-compatible version of 'EitherCodec'
+-- | Either codec
 --
--- > eitherCodec = EitherCodec PossiblyJointUnion
+-- During encoding, parse a value according to either codec.
+-- During encoding, use the corresponding codec to encode either value.
 --
 -- === 'HasCodec' instance for sum types
 --
@@ -488,6 +505,7 @@
 --
 -- @No  ->@ use 'disjointEitherCodec'.
 --
+--
 -- === Example usage
 --
 -- >>> let c = eitherCodec codec codec :: JSONCodec (Either Int String)
@@ -497,80 +515,29 @@
 -- String "hello"
 -- >>> JSON.parseMaybe (parseJSONVia c) (String "world") :: Maybe (Either Int String)
 -- Just (Right "world")
-eitherCodec ::
-  -- |
-  Codec context input1 output1 ->
-  -- |
-  Codec context input2 output2 ->
-  -- |
-  Codec context (Either input1 input2) (Either output1 output2)
-eitherCodec = possiblyJointEitherCodec
-
--- | Forward-compatible version of 'EitherCodec PossiblyJointUnion'
 --
--- > possiblyJointEitherCodec = EitherCodec PossiblyJointUnion
 --
--- === 'HasCodec' instance for sum types with an encoding that is not disjoint.
---
--- The 'eitherCodec' can be used to implement 'HasCodec' instances for sum types.
--- If you just have two codecs that you want to try in order, while parsing, you can do this:
---
--- >>> :{
---   data Ainur
---     = Valar Text Text
---     | Maiar Text
---     deriving (Show, Eq)
--- :}
---
--- >>> :{
---   instance HasCodec Ainur where
---     codec =
---       dimapCodec f g $
---         possiblyJointEitherCodec
---           (object "Valar" $
---             (,)
---              <$> requiredField "domain" "Domain which the Valar rules over" .= fst
---              <*> requiredField "name" "Name of the Valar" .= snd)
---           (object "Maiar" $ requiredField "name" "Name of the Maiar")
---       where
---         f = \case
---           Left (domain, name) -> Valar domain name
---           Right name -> Maiar name
---         g = \case
---           Valar domain name -> Left (domain, name)
---           Maiar name -> Right name
--- :}
---
--- Note that this encoding is indeed not disjoint, because a @Valar@ object can
--- parse as a @Maiar@ value.
---
--- >>> toJSONViaCodec (Valar "Stars" "Varda")
--- Object (fromList [("domain",String "Stars"),("name",String "Varda")])
--- >>> toJSONViaCodec (Maiar "Sauron")
--- Object (fromList [("name",String "Sauron")])
--- >>> JSON.parseMaybe parseJSONViaCodec (Object (Compat.fromList [("name",String "Olorin")])) :: Maybe Ainur
--- Just (Maiar "Olorin")
---
--- === WARNING
+-- ==== API Note
 --
--- The order of the codecs in a 'possiblyJointEitherCodec' matters.
+-- This is a forward-compatible version of 'possiblyJointEitherCodec'.
 --
--- In the above example, decoding works as expected because the @Valar@ case is parsed first.
--- If the @Maiar@ case were first in the 'possiblyJointEitherCodec', then
--- @Valar@ could never be parsed.
-possiblyJointEitherCodec ::
+-- > eitherCodec = possiblyJointEitherCodec
+eitherCodec ::
   -- |
   Codec context input1 output1 ->
   -- |
   Codec context input2 output2 ->
   -- |
   Codec context (Either input1 input2) (Either output1 output2)
-possiblyJointEitherCodec = EitherCodec PossiblyJointUnion
+eitherCodec = possiblyJointEitherCodec
 
--- | Forward-compatible version of 'EitherCodec DisjointUnion'
+-- | Possibly joint either codec
 --
--- > disjointEitherCodec = EitherCodec DisjointUnion
+-- During encoding, parse a value according to either codec.
+-- During encoding, use the corresponding codec to encode either value.
 --
+-- This codec is for the case in which parsing must be disjoint.
+--
 -- === 'HasCodec' instance for sum types with an encoding that is definitely disjoint.
 --
 -- The 'eitherCodec' can be used to implement 'HasCodec' instances sum types
@@ -603,6 +570,7 @@
 -- >>> JSON.parseMaybe parseJSONViaCodec (String "of the roses") :: Maybe War
 -- Just (OtherWar "of the roses")
 --
+--
 -- === WARNING
 --
 -- If it turns out that the encoding of a value is not disjoint, decoding may
@@ -619,12 +587,20 @@
 -- >>> toJSONVia c (Right 6)
 -- Number 6.0
 --
+--
 -- === Example usage
 --
 -- >>> toJSONVia (disjointEitherCodec (codec :: JSONCodec Int) (codec :: JSONCodec String)) (Left 5)
 -- Number 5.0
 -- >>> toJSONVia (disjointEitherCodec (codec :: JSONCodec Int) (codec :: JSONCodec String)) (Right "hello")
 -- String "hello"
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'EitherCodec DisjointUnion'.
+--
+-- > disjointEitherCodec = EitherCodec DisjointUnion
 disjointEitherCodec ::
   -- |
   Codec context input1 output1 ->
@@ -634,6 +610,78 @@
   Codec context (Either input1 input2) (Either output1 output2)
 disjointEitherCodec = EitherCodec DisjointUnion
 
+-- | Possibly joint either codec
+--
+-- During encoding, parse a value according to either codec.
+-- During encoding, use the corresponding codec to encode either value.
+--
+-- This codec is for the case in which parsing may not be disjoint.
+--
+-- === 'HasCodec' instance for sum types with an encoding that is not disjoint.
+--
+-- The 'eitherCodec' can be used to implement 'HasCodec' instances for sum types.
+-- If you just have two codecs that you want to try in order, while parsing, you can do this:
+--
+-- >>> :{
+--   data Ainur
+--     = Valar Text Text
+--     | Maiar Text
+--     deriving (Show, Eq)
+-- :}
+--
+-- >>> :{
+--   instance HasCodec Ainur where
+--     codec =
+--       dimapCodec f g $
+--         possiblyJointEitherCodec
+--           (object "Valar" $
+--             (,)
+--              <$> requiredField "domain" "Domain which the Valar rules over" .= fst
+--              <*> requiredField "name" "Name of the Valar" .= snd)
+--           (object "Maiar" $ requiredField "name" "Name of the Maiar")
+--       where
+--         f = \case
+--           Left (domain, name) -> Valar domain name
+--           Right name -> Maiar name
+--         g = \case
+--           Valar domain name -> Left (domain, name)
+--           Maiar name -> Right name
+-- :}
+--
+-- Note that this encoding is indeed not disjoint, because a @Valar@ object can
+-- parse as a @Maiar@ value.
+--
+-- >>> toJSONViaCodec (Valar "Stars" "Varda")
+-- Object (fromList [("domain",String "Stars"),("name",String "Varda")])
+-- >>> toJSONViaCodec (Maiar "Sauron")
+-- Object (fromList [("name",String "Sauron")])
+-- >>> JSON.parseMaybe parseJSONViaCodec (Object (Compat.fromList [("name",String "Olorin")])) :: Maybe Ainur
+-- Just (Maiar "Olorin")
+--
+--
+-- === WARNING
+--
+-- The order of the codecs in a 'possiblyJointEitherCodec' matters.
+--
+-- In the above example, decoding works as expected because the @Valar@ case is parsed first.
+-- If the @Maiar@ case were first in the 'possiblyJointEitherCodec', then
+-- @Valar@ could never be parsed.
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'EitherCodec PossiblyJointUnion'.
+--
+-- > possiblyJointEitherCodec = EitherCodec PossiblyJointUnion
+possiblyJointEitherCodec ::
+  -- |
+  Codec context input1 output1 ->
+  -- |
+  Codec context input2 output2 ->
+  -- |
+  Codec context (Either input1 input2) (Either output1 output2)
+possiblyJointEitherCodec = EitherCodec PossiblyJointUnion
+
 -- | Map a codec's input and output types.
 --
 -- This function allows you to have the parsing fail in a new way.
@@ -642,6 +690,7 @@
 --
 -- This function is like 'BimapCodec' except it also combines one level of a nested 'BimapCodec's.
 --
+--
 -- === Example usage
 --
 -- logLevelCodec :: JSONCodec LogLevel
@@ -651,36 +700,61 @@
   (newInput -> oldInput) ->
   Codec context oldInput oldOutput ->
   Codec context newInput newOutput
-bimapCodec f g = \case
-  BimapCodec f' g' c -> BimapCodec (f' >=> f) (g' . g) c
-  c -> BimapCodec f g c
+bimapCodec f g =
+  -- We distinguish between a 'BimapCodec' and a non-'BimapCodec' just so that
+  -- we don't introduce additional layers that we can already combine anyway.
+  \case
+    BimapCodec f' g' c -> BimapCodec (f' >=> f) (g' . g) c
+    c -> BimapCodec f g c
 
--- | Forward-compatible version of 'ArrayOfCodec' without a name
+-- | Vector codec
 --
--- > vectorCodec = ArrayOfCodec Nothing
+-- Build a codec for vectors of values from a codec for a single value.
 --
+--
 -- === Example usage
 --
 -- >>> toJSONVia (vectorCodec codec) (Vector.fromList ['a','b'])
 -- Array [String "a",String "b"]
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'ArrayOfCodec' without a name.
+--
+-- > vectorCodec = ArrayOfCodec Nothing
 vectorCodec :: ValueCodec input output -> ValueCodec (Vector input) (Vector output)
 vectorCodec = ArrayOfCodec Nothing
 
--- | Build a codec for lists of values from a codec for a single value.
+-- | List codec
 --
+-- Build a codec for lists of values from a codec for a single value.
+--
+--
 -- === Example usage
 --
 -- >>> toJSONVia (listCodec codec) ['a','b']
 -- Array [String "a",String "b"]
+--
+--
+-- ==== API Note
+--
+-- This is the list version of 'vectorCodec'.
 listCodec :: ValueCodec input output -> ValueCodec [input] [output]
 listCodec = dimapCodec V.toList V.fromList . vectorCodec
 
 -- | Build a codec for nonempty lists of values from a codec for a single value.
 --
+--
 -- === Example usage
 --
 -- >>> toJSONVia (nonEmptyCodec codec) ('a' :| ['b'])
 -- Array [String "a",String "b"]
+--
+--
+-- ==== API Note
+--
+-- This is the non-empty list version of 'vectorCodec'.
 nonEmptyCodec :: ValueCodec input output -> ValueCodec (NonEmpty input) (NonEmpty output)
 nonEmptyCodec = bimapCodec parseNonEmptyList NE.toList . listCodec
   where
@@ -688,11 +762,15 @@
       Nothing -> Left "Expected a nonempty list, but got an empty list."
       Just ne -> Right ne
 
--- | Like 'listCodec', except the values may also be simplified as a single value.
+-- | Single or list codec
 --
+-- This codec behaves like 'listCodec', except the values may also be
+-- simplified as a single value.
+--
 -- During parsing, a single element may be parsed as the list of just that element.
 -- During rendering, a list with only one element will be rendered as just that element.
 --
+--
 -- === Example usage
 --
 -- >>> let c = singleOrListCodec codec :: JSONCodec [Int]
@@ -705,6 +783,7 @@
 -- >>> JSON.parseMaybe (parseJSONVia c) (Array [Number 5, Number 6]) :: Maybe [Int]
 -- Just [5,6]
 --
+--
 -- === WARNING
 --
 -- If you use nested lists, for example when the given value codec is also a
@@ -719,11 +798,15 @@
       [v] -> Left v
       vs -> Right vs
 
--- | Like 'nonEmptyCodec', except the values may also be simplified as a single value.
+-- | Single or nonempty list codec
 --
+-- This codec behaves like 'nonEmptyCodec', except the values may also be
+-- simplified as a single value.
+--
 -- During parsing, a single element may be parsed as the list of just that element.
 -- During rendering, a list with only one element will be rendered as just that element.
 --
+--
 -- === Example usage
 --
 -- >>> let c = singleOrNonEmptyCodec codec :: JSONCodec (NonEmpty Int)
@@ -736,10 +819,15 @@
 -- >>> JSON.parseMaybe (parseJSONVia c) (Array [Number 5, Number 6]) :: Maybe (NonEmpty Int)
 -- Just (5 :| [6])
 --
+--
 -- === WARNING
 --
 -- If you use nested lists, for example when the given value codec is also a
 -- 'nonEmptyCodec', you may get in trouble with ambiguities during parsing.
+--
+-- ==== API Note
+--
+-- This is a nonempty version of 'singleOrListCodec'.
 singleOrNonEmptyCodec :: ValueCodec input output -> ValueCodec (NonEmpty input) (NonEmpty output)
 singleOrNonEmptyCodec c = dimapCodec f g $ eitherCodec c $ nonEmptyCodec c
   where
@@ -860,6 +948,8 @@
   ObjectCodec output output
 optionalFieldWithOmittedDefaultWith' key c defaultValue = OptionalKeyWithOmittedDefaultCodec key c defaultValue Nothing
 
+-- | Like 'optionalFieldWithOmittedDefaultWith', but the value may also be
+-- @null@ and that will be interpreted as the default value.
 optionalFieldOrNullWithOmittedDefaultWith ::
   Eq output =>
   -- | Key
@@ -878,6 +968,8 @@
       Nothing -> defaultValue
     g v = if v == defaultValue then Nothing else Just v
 
+-- | Like 'optionalFieldWithOmittedDefaultWith'', but the value may also be
+-- @null@ and that will be interpreted as the default value.
 optionalFieldOrNullWithOmittedDefaultWith' ::
   Eq output =>
   -- | Key
@@ -942,8 +1034,11 @@
 
 -- | Encode a 'HashMap', and decode any 'HashMap'.
 --
--- Forward-compatible version of 'HashMapCodec'
 --
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'HashMapCodec'.
+--
 -- > hashMapCodec = HashMapCodec
 hashMapCodec ::
   (Eq k, Hashable k, FromJSONKey k, ToJSONKey k) =>
@@ -955,8 +1050,11 @@
 
 -- | Encode a 'Map', and decode any 'Map'.
 --
--- Forward-compatible version of 'MapCodec'
 --
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'MapCodec'.
+--
 -- > mapCodec = MapCodec
 mapCodec ::
   (Ord k, FromJSONKey k, ToJSONKey k) =>
@@ -982,20 +1080,23 @@
   Nothing -> dimapCodec KM.fromHashMap KM.toHashMap . hashMapCodec
 #endif
 
--- | Forward-compatible version of 'ValueCodec'
---
--- > valueCodec = ValueCodec
+-- | Codec for a 'JSON.Value'
 --
 -- This is essentially your escape-hatch for when you would normally need a monad instance for 'Codec'.
 -- You can build monad parsing by using 'valueCodec' together with 'bimapCodec' and supplying your own parsing function.
 --
 -- Note that this _does_ mean that the documentation will just say that you are parsing and rendering a value, so you may want to document the extra parsing further using '<?>'.
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'ValueCodec'.
+--
+-- > valueCodec = ValueCodec
 valueCodec :: JSONCodec JSON.Value
 valueCodec = ValueCodec
 
--- | Forward-compatible version of 'NullCodec'
+-- | Codec for @null@
 --
--- > nullCodec = NullCodec
 --
 -- === Example usage
 --
@@ -1005,49 +1106,76 @@
 -- Just ()
 -- >>> JSON.parseMaybe (parseJSONVia nullCodec) (Number 5)
 -- Nothing
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'NullCodec'.
+--
+-- > nullCodec = NullCodec
 nullCodec :: JSONCodec ()
 nullCodec = NullCodec
 
--- | Forward-compatible version of 'BoolCodec' without a name
+-- | Codec for boolean values
 --
--- > boolCodec = BoolCodec Nothing
 --
 -- === Example usage
 --
 -- >>> toJSONVia boolCodec True
 -- Bool True
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'BoolCodec' without a name.
+--
+-- > boolCodec = BoolCodec Nothing
 boolCodec :: JSONCodec Bool
 boolCodec = BoolCodec Nothing
 
--- | Forward-compatible version of 'StringCodec' without a name
+-- | Codec for text values
 --
--- > textCodec = StringCodec Nothing
 --
 -- === Example usage
 --
 -- >>> toJSONVia textCodec "hello"
 -- String "hello"
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'StringCodec' without a name.
+--
+-- > textCodec = StringCodec Nothing
 textCodec :: JSONCodec Text
 textCodec = StringCodec Nothing
 
--- | A 'String' version of 'textCodec'.
+-- | Codec for 'String' values
 --
+--
 -- === Example usage
 --
 -- >>> toJSONVia stringCodec "hello"
 -- String "hello"
 --
+--
 -- === WARNING
 --
 -- This codec uses 'T.unpack' and 'T.pack' to dimap a 'textCodec', so it __does not roundtrip__.
 --
 -- >>> toJSONVia stringCodec "\55296"
 -- String "\65533"
+--
+--
+-- ==== API Note
+--
+-- This is a 'String' version of 'textCodec'.
 stringCodec :: JSONCodec String
 stringCodec = dimapCodec T.unpack T.pack textCodec
 
--- | Forward-compatible version of 'NumberCodec' without a name
+-- | Codec for 'Scientific' values
 --
+--
 -- === Example usage
 --
 -- > scientificCodec = NumberCodec Nothing Nothing
@@ -1055,6 +1183,7 @@
 -- >>> toJSONVia scientificCodec 5
 -- Number 5.0
 --
+--
 -- === WARNING
 --
 -- 'Scientific' is a type that is only for JSON parsing and rendering.
@@ -1065,12 +1194,18 @@
 -- λ> (1 / 3) :: Scientific
 -- *** Exception: fromRational has been applied to a repeating decimal which can't be represented as a Scientific! It's better to avoid performing fractional operations on Scientifics and convert them to other fractional types like Double as early as possible.
 -- @
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'NumberCodec' without a name.
+--
+-- > scientificCodec = NumberCodec Nothing Nothing
 scientificCodec :: JSONCodec Scientific
 scientificCodec = NumberCodec Nothing Nothing
 
 -- | An object codec with a given name
 --
--- > object name = ObjectOfCodec (Just name)
 --
 -- === Example usage
 --
@@ -1085,6 +1220,13 @@
 -- >       Example
 -- >         <$> requiredField "text" "a text" .= exampleText
 -- >         <*> requiredField "bool" "a bool" .= exampleBool
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version 'ObjectOfCodec' with a name.
+--
+-- > object name = ObjectOfCodec (Just name)
 object :: Text -> ObjectCodec input output -> ValueCodec input output
 object name = ObjectOfCodec (Just name)
 
@@ -1127,6 +1269,7 @@
 --
 -- During rendering, the given 'Text' is always output.
 --
+--
 -- === Example usage
 --
 -- >>> let c = literalTextCodec "hello"
@@ -1147,6 +1290,7 @@
 --
 -- During rendering, the given @value@ is always output.
 --
+--
 -- === Example usage
 --
 -- >>> let c = literalTextValueCodec True "yes"
@@ -1161,7 +1305,7 @@
 literalTextValueCodec :: value -> Text -> JSONCodec value
 literalTextValueCodec value text = dimapCodec (const value) (const text) (literalTextCodec text)
 
--- | A choice codec, but unlike 'eitherCodec', it's for the same type instead of different ones.
+-- | A choice codec, but unlike 'eitherCodec', it's for the same output type instead of different ones.
 --
 -- While parsing, this codec will first try the left codec, then the right if that fails.
 --
@@ -1170,6 +1314,7 @@
 -- Note: The reason this is less primitive than the 'eitherCodec' is that 'Either' makes it clear which codec you want to use for rendering.
 -- In this case, we need to provide our own function for choosing which codec we want to use for rendering.
 --
+--
 -- === Example usage
 --
 -- >>> :{
@@ -1188,29 +1333,66 @@
 -- Just "even"
 -- >>> JSON.parseMaybe (parseJSONVia c) (String "odd") :: Maybe Text
 -- Just "odd"
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'matchChoiceCodecAs PossiblyJointUnion':
+--
+-- > disjointMatchChoiceCodec = matchChoiceCodecAs PossiblyJointUnion
 matchChoiceCodec ::
   -- | First codec
   Codec context input output ->
   -- | Second codec
+  Codec context input' output ->
+  -- | Rendering chooser
+  (newInput -> Either input input') ->
+  -- |
+  Codec context newInput output
+matchChoiceCodec = matchChoiceCodecAs PossiblyJointUnion
+
+-- | Disjoint version of 'matchChoiceCodec'
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'matchChoiceCodecAs DisjointUnion':
+--
+-- > disjointMatchChoiceCodec = matchChoiceCodecAs DisjointUnion
+disjointMatchChoiceCodec ::
+  -- | First codec
   Codec context input output ->
+  -- | Second codec
+  Codec context input' output ->
   -- | Rendering chooser
-  (newInput -> Either input input) ->
+  (newInput -> Either input input') ->
   -- |
   Codec context newInput output
-matchChoiceCodec c1 c2 renderingChooser =
-  dimapCodec f renderingChooser $
-    eitherCodec c1 c2
-  where
-    f = \case
-      Left a -> a
-      Right a -> a
+disjointMatchChoiceCodec = matchChoiceCodecAs DisjointUnion
 
+-- | An even more general version of 'matchChoiceCodec' and 'disjointMatchChoiceCodec'.
+matchChoiceCodecAs ::
+  -- | Is the union DisjointUnion or PossiblyJointUnion
+  Union ->
+  -- | First codec
+  Codec context input output ->
+  -- | Second codec
+  Codec context input' output ->
+  -- | Rendering chooser
+  (newInput -> Either input input') ->
+  -- |
+  Codec context newInput output
+matchChoiceCodecAs union c1 c2 renderingChooser =
+  dimapCodec (either id id) renderingChooser $
+    EitherCodec union c1 c2
+
 -- | A choice codec for a list of options, each with their own rendering matcher.
 --
 -- During parsing, each of the codecs are tried from first to last until one succeeds.
 --
 -- During rendering, each matching function is tried until either one succeeds and the corresponding codec is used, or none succeed and the fallback codec is used.
 --
+--
 -- === Example usage
 --
 -- >>> :{
@@ -1235,6 +1417,13 @@
 -- Nothing
 -- >>> JSON.parseMaybe (parseJSONVia c) (String "fallback") :: Maybe Text
 -- Just "fallback"
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'matchChoicesCodecAs DisjointUnion'.
+--
+-- > disjointMatchChoiceCodec = matchChoicesCodecAs DisjointUnion
 matchChoicesCodec ::
   -- | Codecs, each which their own rendering matcher
   [(input -> Maybe input, Codec context input output)] ->
@@ -1242,11 +1431,39 @@
   Codec context input output ->
   -- |
   Codec context input output
-matchChoicesCodec l fallback = go l
+matchChoicesCodec = matchChoicesCodecAs PossiblyJointUnion
+
+-- | Disjoint version of 'matchChoicesCodec'
+--
+--
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'matchChoicesCodecAs DisjointUnion'.
+--
+-- > disjointMatchChoiceCodec = matchChoicesCodecAs DisjointUnion
+disjointMatchChoicesCodec ::
+  -- | Codecs, each which their own rendering matcher
+  [(input -> Maybe input, Codec context input output)] ->
+  -- | Fallback codec, in case none of the matchers in the list match
+  Codec context input output ->
+  -- |
+  Codec context input output
+disjointMatchChoicesCodec = matchChoicesCodecAs DisjointUnion
+
+-- | An even more general version of 'matchChoicesCodec' and 'disjointMatchChoicesCodec'
+matchChoicesCodecAs ::
+  Union ->
+  -- | Codecs, each which their own rendering matcher
+  [(input -> Maybe input, Codec context input output)] ->
+  -- | Fallback codec, in case none of the matchers in the list match
+  Codec context input output ->
+  -- |
+  Codec context input output
+matchChoicesCodecAs union l fallback = go l
   where
     go = \case
       [] -> fallback
-      ((m, c) : rest) -> matchChoiceCodec c (go rest) $ \i -> case m i of
+      ((m, c) : rest) -> matchChoiceCodecAs union c (go rest) $ \i -> case m i of
         Just j -> Left j
         Nothing -> Right i
 
@@ -1255,6 +1472,7 @@
 --
 -- You can use this for keeping old ways of parsing intact while already rendering in the new way.
 --
+--
 -- === Example usage
 --
 -- >>> data Fruit = Apple | Orange deriving (Show, Eq, Bounded, Enum)
@@ -1281,6 +1499,7 @@
 
 -- | Like 'parseAlternatives', but with only one alternative codec
 --
+--
 -- === Example usage
 --
 -- >>> data Fruit = Apple | Orange deriving (Show, Eq, Bounded, Enum)
@@ -1301,6 +1520,7 @@
 
 -- | A codec for an enum that can be written each with their own codec.
 --
+--
 -- === WARNING
 --
 -- If you don't provide a string for one of the type's constructors, the last codec in the list will be used instead.
@@ -1316,13 +1536,14 @@
     go :: NonEmpty (enum, Codec context enum enum) -> Codec context enum enum
     go ((e, c) :| rest) = case NE.nonEmpty rest of
       Nothing -> c
-      Just ne -> matchChoiceCodec c (go ne) $ \i ->
+      Just ne -> disjointMatchChoiceCodec c (go ne) $ \i ->
         if e == i
           then Left e
           else Right i
 
 -- | A codec for an enum that can be written as constant string values
 --
+--
 -- === Example usage
 --
 -- >>> data Fruit = Apple | Orange deriving (Show, Eq)
@@ -1332,6 +1553,7 @@
 -- >>> JSON.parseMaybe (parseJSONVia c) (String "foo") :: Maybe Fruit
 -- Just Apple
 --
+--
 -- === WARNING
 --
 -- If you don't provide a string for one of the type's constructors, the last string in the list will be used instead:
@@ -1357,6 +1579,7 @@
 
 -- | A codec for a 'Bounded' 'Enum' that uses its 'Show' instance to have the values correspond to literal 'Text' values.
 --
+--
 -- === Example usage
 --
 -- >>> data Fruit = Apple | Orange deriving (Show, Eq, Enum, Bounded)
@@ -1399,8 +1622,11 @@
 -- This is used to allow for references to the codec, and that's necessary
 -- to produce finite documentation for recursive codecs.
 --
--- Forward-compatible version of 'ReferenceCodec'
 --
+-- ==== API Note
+--
+-- This is a forward-compatible version of 'ReferenceCodec'.
+--
 -- > named = ReferenceCodec
 named :: Text -> ValueCodec input output -> ValueCodec input output
 named = ReferenceCodec
@@ -1412,6 +1638,7 @@
 --
 -- Note that this will not have good documentation because, at a codec level,
 -- it's just parsing and rendering a 'JSON.Value'.
+--
 --
 -- === Example usage
 --
