diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,14 @@
 # Revision history for mmzk-typeid
 
 
-## 0.7.0.0 -- Unreleased
+## 0.7.0.0 -- 2024-07-03
 
-* Use `String`s instead of `Text`s inside the constructors of `TypeIDError` so that it is eaiser to use the promoted constructors.
+* Use `String`s instead of `Text`s inside the constructors of `TypeIDError` so that it is easier to use the promoted constructors.
+
+* More complete compile-time error messages for `KindID` errors.
+
+* Hide away internal type-level programming details from Haddock.
+  * Many of the type-level helper declarations are now internal.
 
 
 ## 0.6.3.1 -- 2024-06-23
diff --git a/mmzk-typeid.cabal b/mmzk-typeid.cabal
--- a/mmzk-typeid.cabal
+++ b/mmzk-typeid.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               mmzk-typeid
-version:            0.6.3.1
+version:            0.7.0.0
 
 synopsis:           A TypeID and UUIDv7 implementation for Haskell
 description:
@@ -74,6 +74,7 @@
         Data.UUID.V7,
         Data.UUID.Versions
     other-modules:
+        Data.KindID.Error,
         Data.KindID.Internal,
         Data.TypeID.Internal
     default-extensions:
@@ -119,6 +120,7 @@
     other-modules:
         Data.KindID,
         Data.KindID.Class,
+        Data.KindID.Error,
         Data.KindID.Internal,
         Data.KindID.Unsafe,
         Data.KindID.V1,
diff --git a/src/Data/KindID/Class.hs b/src/Data/KindID/Class.hs
--- a/src/Data/KindID/Class.hs
+++ b/src/Data/KindID/Class.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE UndecidableInstances #-}
 
 -- |
@@ -14,25 +15,16 @@
   -- * Prefix
     ValidPrefix
   , ToPrefix(..)
-  -- * Helpers
-  , LengthLT64C
-  , IsLUSymbolC
-  , LengthSymbol
-  , IsLowerChar
-  , IsUnderscore
-  , IsLUSymbol
-  , ILUSUH1
-  , ILUSUH2
-  -- * Deprecated Helpers
-  , IsLowerSymbol
-  , LSUH
-  , ILSUH
   ) where
 
+#ifndef __HADDOCK_VERSION__
 import           Data.Kind
+import           Data.KindID.Error
 import           Data.Type.Bool
 import           Data.Type.Equality
 import           Data.Type.Ord
+import           Data.TypeID.Error
+#endif
 import           GHC.TypeLits
 
 -- | A class that translates any kind to a 'Symbol'. It is used to translate
@@ -66,6 +58,7 @@
 -- >   commentID <- genKindID @'Comment   -- Same as genKindID @"comment"
 -- >   suID      <- genKindID @'SuperUser -- Same as genKindID @"super_user"
 class ToPrefix a where
+  -- | The associated type family that converts @a@ into a 'Symbol'.
   type PrefixSymbol a :: Symbol
 
 -- | The 'PrefixSymbol' of a 'Symbol' is the 'Symbol' itself.
@@ -73,76 +66,28 @@
   type PrefixSymbol s = s
 
 -- | A constraint for valid prefix 'Symbol's.
+--
+#ifndef __HADDOCK_VERSION__
 type ValidPrefix prefix = ( KnownSymbol prefix
                           , LengthLT64C prefix
                           , IsLUSymbolC prefix )
+#else
+-- Note that this is __NOT__ the actual definition! Its true definition is
+-- hidden here in the documentation as it uses internal type-level helpers that
+-- we do not expose and make no guarantee on their In practice, any prefix with
+-- this constraint is a valid prefix for a 'Data.KindID.KindID'.
+type ValidPrefix prefix = KnownSymbol prefix
+#endif
 
+#ifndef __HADDOCK_VERSION__
 -- | Contains a custom error message if the prefix 'Symbol' is too long.
 type family LengthLT64C (prefix :: Symbol) :: Constraint where
   LengthLT64C s
     = If (Compare (LengthSymbol s) 64 == 'LT) (() :: Constraint)
-         ( TypeError ( Text "The prefix "
-                  :<>: ShowType s
-                  :<>: Text " with "
-                  :<>: ShowType (LengthSymbol s)
-                  :<>: Text " characters is too long!" ) )
+         (TypeError (ToErrorMessage ('TypeIDErrorPrefixTooLong (Sym2Str s))))
 
 -- | Contains a custom error message if the prefix 'Symbol' is not lowercase +
 -- underscore or it starts or ends with underscores.
 type family IsLUSymbolC (prefix :: Symbol) :: Constraint where
-  IsLUSymbolC s
-    = If (IsLUSymbol s) (() :: Constraint)
-         ( TypeError ( Text "The prefix "
-                  :<>: ShowType s
-                  :<>: Text " is not valid!" ) )
-
--- | The length of a 'Symbol' as a 'Nat'.
-type family LengthSymbol (prefix :: Symbol) :: Nat where
-  LengthSymbol prefix = LSUH (UnconsSymbol prefix)
-
--- | LengthSymbol Uncons Helper.
-type family LSUH (uncons :: Maybe (Char, Symbol)) :: Nat where
-  LSUH 'Nothing          = 0
-  LSUH ('Just '( c, s )) = 1 + LengthSymbol s
-
--- | Is a type-level 'Char' lowercase?
-type family IsLowerChar (ch :: Char) :: Bool where
-  IsLowerChar ch = Compare '`' ch == 'LT && Compare ch '{' == 'LT
-
--- | Is a type-level 'Char' an underscore?
-type family IsUnderscore (ch :: Char) :: Bool where
-  IsUnderscore ch = Compare '_' ch == 'EQ
-
--- | Is a 'Symbol' lowercase + underscore and not start or end with underscores?
-type family IsLUSymbol (prefix :: Symbol) :: Bool where
-  IsLUSymbol prefix = ILUSUH1 (UnconsSymbol prefix)
-
--- | First IsLUSymbol Uncons Helper.
-type family ILUSUH1 (uncons :: Maybe (Char, Symbol)) :: Bool where
-  ILUSUH1 'Nothing            = True
-  ILUSUH1 ('Just '( '_', _ )) = False
-  ILUSUH1 ('Just '( c, s ))   = (IsLowerChar c || IsUnderscore c)
-                             && ILUSUH2 (UnconsSymbol s)
-
--- | Second IsLUSymbol Uncons Helper.
-type family ILUSUH2 (uncons :: Maybe (Char, Symbol)) :: Bool where
-  ILUSUH2 'Nothing           = True
-  ILUSUH2 ('Just '( c, "" )) = IsLowerChar c
-  ILUSUH2 ('Just '( c, s ))  = (IsLowerChar c || IsUnderscore c)
-                            && ILUSUH2 (UnconsSymbol s)
-
-
---------------------------------------------------------------------------------
--- Deprecated
---------------------------------------------------------------------------------
-
--- | Is a 'Symbol' lowercase?
-type family IsLowerSymbol (prefix :: Symbol) :: Bool where
-  IsLowerSymbol prefix = ILSUH (UnconsSymbol prefix)
-{-# DEPRECATED IsLowerSymbol "No longer used; to be removed in version 0.7" #-}
-
--- | Is LowerSymbol Uncons Helper.
-type family ILSUH (uncons :: Maybe (Char, Symbol)) :: Bool where
-  ILSUH 'Nothing          = 'True
-  ILSUH ('Just '( c, s )) = IsLowerChar c && IsLowerSymbol s
-{-# DEPRECATED ILSUH "No longer used; to be removed in the version 0.7" #-}
+  IsLUSymbolC s = BuildTypeIDErrorConstraint (IsLUSymbol s)
+#endif
diff --git a/src/Data/KindID/Error.hs b/src/Data/KindID/Error.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/KindID/Error.hs
@@ -0,0 +1,124 @@
+{-# LANGUAGE UndecidableInstances #-}
+
+-- | An internal module to provide better compilation errors for invalid
+-- 'Data.KindID.V7.KindID' prefixes.
+--
+module Data.KindID.Error where
+
+import           Data.Kind
+import           Data.TypeID.Error
+import           Data.Type.Bool
+import           Data.Type.Equality
+import           Data.Type.Ord
+import           GHC.TypeLits
+
+-- | A class that covnerts a poly-kind into an "ErrorMessage".
+--
+-- Used for converting type-level "TypeIDError"s into custom compile-time error
+-- messages.
+class ToErrorMessageC (e :: k) where
+  type ToErrorMessage e :: ErrorMessage
+
+instance ToErrorMessageC (TypeIDErrorPrefixTooLong t) where
+  type ToErrorMessage (TypeIDErrorPrefixTooLong t) =
+        Text "The prefix "
+   :<>: ShowType (Str2Sym t)
+   :<>: Text " with "
+   :<>: ShowType (LengthSymbol (Str2Sym t))
+   :<>: Text " characters is too long!"
+
+instance ToErrorMessageC TypeIDExtraSeparator where
+  type ToErrorMessage TypeIDExtraSeparator = Text
+    "The underscore separator should not be present if the prefix is empty!"
+
+instance ToErrorMessageC (TypeIDStartWithUnderscore t) where
+  type ToErrorMessage (TypeIDStartWithUnderscore t) =
+        Text "The prefix "
+   :<>: ShowType (Str2Sym t)
+   :<>: Text " should not start with an underscore!"
+
+instance ToErrorMessageC (TypeIDEndWithUnderscore t) where
+  type ToErrorMessage (TypeIDEndWithUnderscore t) =
+        Text "The prefix "
+   :<>: ShowType (Str2Sym t)
+   :<>: Text " should not end with an underscore!"
+
+instance ToErrorMessageC (TypeIDErrorPrefixInvalidChar t c) where
+  type ToErrorMessage (TypeIDErrorPrefixInvalidChar t c) =
+        Text "The prefix "
+   :<>: ShowType (Str2Sym t)
+   :<>: Text " contains invalid character "
+   :<>: ShowType c
+   :<>: Text "!"
+
+type family Str2Sym (str :: String) :: Symbol where
+  Str2Sym '[]       = ""
+  Str2Sym (c ': cs) = ConsSymbol c (Str2Sym cs)
+
+type family Sym2Str (str :: Symbol) :: String where
+  Sym2Str s = SSUH (UnconsSymbol s)
+
+type family SSUH (uncons :: Maybe (Char, Symbol)) :: String where
+  SSUH Nothing          = '[]
+  SSUH (Just '( c, s )) = c ': Sym2Str s
+
+-- | The length of a 'Symbol' as a 'Nat'.
+type family LengthSymbol (prefix :: Symbol) :: Nat where
+  LengthSymbol prefix = LSUH (UnconsSymbol prefix)
+
+-- | LengthSymbol Uncons Helper.
+type family LSUH (uncons :: Maybe (Char, Symbol)) :: Nat where
+  LSUH 'Nothing          = 0
+  LSUH ('Just '( c, s )) = 1 + LengthSymbol s
+
+-- | Is a type-level 'Char' lowercase?
+type family IsLowerChar (ch :: Char) :: Bool where
+  IsLowerChar ch = Compare '`' ch == 'LT && Compare ch '{' == 'LT
+
+-- | Is a type-level 'Char' an underscore?
+type family IsUnderscore (ch :: Char) :: Bool where
+  IsUnderscore ch = Compare '_' ch == 'EQ
+
+-- | Is a 'Symbol' lowercase + underscore and not start or end with underscores?
+--
+-- ''Nothing' if no error; otherwise ''Just' a 'TypeIDError'.
+type family IsLUSymbol (prefix :: Symbol) :: Maybe TypeIDError where
+  IsLUSymbol "_"    = 'Just 'TypeIDExtraSeparator
+  IsLUSymbol prefix = ILUSUH1 (UnconsSymbol prefix) prefix
+
+-- | First IsLUSymbol Uncons Helper.
+type family ILUSUH1 (uncons :: Maybe (Char, Symbol)) (prefix :: Symbol)
+  :: Maybe TypeIDError where
+    ILUSUH1 'Nothing s            = 'Nothing
+    ILUSUH1 ('Just '( '_', _ )) s = 'Just
+      (TypeIDStartWithUnderscore (Sym2Str s))
+    ILUSUH1 ('Just '( c, r )) s   =
+          WrapMaybe (IsLowerChar c || IsUnderscore c)
+                    (TypeIDErrorPrefixInvalidChar (Sym2Str s) c)
+      <|> ILUSUH2 (UnconsSymbol r) s
+
+-- | Second IsLUSymbol Uncons Helper.
+type family ILUSUH2 (uncons :: Maybe (Char, Symbol)) (prefix :: Symbol)
+  :: Maybe TypeIDError where
+    ILUSUH2 'Nothing s             = 'Nothing
+    ILUSUH2 ('Just '( '_', "" )) s = 'Just (TypeIDEndWithUnderscore (Sym2Str s))
+    ILUSUH2 ('Just '( c, r )) s    =
+          WrapMaybe (IsLowerChar c || IsUnderscore c)
+                    (TypeIDErrorPrefixInvalidChar (Sym2Str s) c)
+      <|> ILUSUH2 (UnconsSymbol r) s
+
+-- | @wrapMaybe True _ = Nothing; wrapMaybe False x = Just x@.
+type family WrapMaybe p a where
+  WrapMaybe True a  = 'Nothing
+  WrapMaybe False a = 'Just a
+
+-- | Type-level '(<|>)' for 'Maybe'.
+type family (<|>) a b where
+  'Just a <|> b = 'Just a
+  Nothing <|> b = b
+
+-- | Turn a type-level 'Maybe' 'TypeIDError' into a 'TypeError'.
+type family BuildTypeIDErrorConstraint (a :: Maybe TypeIDError)
+  :: Constraint where
+    BuildTypeIDErrorConstraint 'Nothing  = ()
+    BuildTypeIDErrorConstraint ('Just e) = TypeError (ToErrorMessage e)
diff --git a/src/Data/KindID/Internal.hs b/src/Data/KindID/Internal.hs
--- a/src/Data/KindID/Internal.hs
+++ b/src/Data/KindID/Internal.hs
@@ -458,8 +458,8 @@
   tid <- TID.parseString str
   case fromTypeID tid of
     Nothing  -> Left $ TypeIDErrorPrefixMismatch
-                       (T.pack (symbolVal (Proxy @(PrefixSymbol prefix))))
-                       (getPrefix tid)
+                       (symbolVal (Proxy @(PrefixSymbol prefix)))
+                       (T.unpack $ getPrefix tid)
     Just kid -> pure kid
 {-# INLINE parseString #-}
 
@@ -472,8 +472,8 @@
   tid <- TID.parseText str
   case fromTypeID tid of
     Nothing  -> Left $ TypeIDErrorPrefixMismatch
-                       (T.pack (symbolVal (Proxy @(PrefixSymbol prefix))))
-                       (getPrefix tid)
+                       (symbolVal (Proxy @(PrefixSymbol prefix)))
+                       (T.unpack $ getPrefix tid)
     Just kid -> pure kid
 {-# INLINE parseText #-}
 
@@ -486,8 +486,8 @@
   tid <- TID.parseByteString str
   case fromTypeID tid of
     Nothing  -> Left $ TypeIDErrorPrefixMismatch
-                       (T.pack (symbolVal (Proxy @(PrefixSymbol prefix))))
-                       (getPrefix tid)
+                       (symbolVal (Proxy @(PrefixSymbol prefix)))
+                       (T.unpack $ getPrefix tid)
     Just kid -> pure kid
 {-# INLINE parseByteString #-}
 
diff --git a/src/Data/TypeID/Error.hs b/src/Data/TypeID/Error.hs
--- a/src/Data/TypeID/Error.hs
+++ b/src/Data/TypeID/Error.hs
@@ -13,8 +13,6 @@
  ) where
 
 import           Control.Exception
-import           Data.Text (Text)
-import qualified Data.Text as T
 
 -- | Errors from parsing TypeIDs.
 --
@@ -22,18 +20,18 @@
 -- exact output format may differ across library versions.
 data TypeIDError
   = -- | The prefix is longer than 63 characters.
-    TypeIDErrorPrefixTooLong Text
+    TypeIDErrorPrefixTooLong String
     -- | The ID contains an extra underscore separator.
   | TypeIDExtraSeparator
     -- | The ID starts with an underscore separator.
-  | TypeIDStartWithUnderscore Text
+  | TypeIDStartWithUnderscore String
     -- | The ID ends with an underscore separator.
-  | TypeIDEndWithUnderscore Text
+  | TypeIDEndWithUnderscore String
     -- | The prefix contains an invalid character, namely not lowercase Latin.
-  | TypeIDErrorPrefixInvalidChar Text Char
+  | TypeIDErrorPrefixInvalidChar String Char
     -- | From a 'Data.KindID.V7KindID' conversion. The prefix doesn't match with
     -- the expected.
-  | TypeIDErrorPrefixMismatch Text Text
+  | TypeIDErrorPrefixMismatch String String
     -- | The 'Data.UUID.Types.Internal.UUID' suffix has errors.
   | TypeIDErrorUUIDError
   deriving (Eq, Ord)
@@ -42,7 +40,7 @@
   show :: TypeIDError -> String
   show (TypeIDErrorPrefixTooLong txt)
     = concat [ "The prefix ", show txt
-             , " with ", show (T.length txt), " characters is too long!" ]
+             , " with ", show (length txt), " characters is too long!" ]
   show TypeIDExtraSeparator
     = "The underscore separator should not be present if the prefix is empty!"
   show (TypeIDStartWithUnderscore txt)
diff --git a/src/Data/TypeID/Internal.hs b/src/Data/TypeID/Internal.hs
--- a/src/Data/TypeID/Internal.hs
+++ b/src/Data/TypeID/Internal.hs
@@ -543,16 +543,18 @@
 -- | Check if the given prefix is a valid 'TypeID'' prefix.
 checkPrefix :: Text -> Maybe TypeIDError
 checkPrefix prefix
-  | T.length prefix > 63 = Just $ TypeIDErrorPrefixTooLong prefix
+  | T.length prefix > 63 = Just $ TypeIDErrorPrefixTooLong prefixStr
   | T.null prefix        = Nothing
-  | T.head prefix == '_' = Just $ TypeIDStartWithUnderscore prefix
-  | T.last prefix == '_' = Just $ TypeIDEndWithUnderscore prefix
+  | T.head prefix == '_' = Just $ TypeIDStartWithUnderscore prefixStr
+  | T.last prefix == '_' = Just $ TypeIDEndWithUnderscore prefixStr
   | otherwise
       = case T.uncons ( T.dropWhile ( liftM2 (||) (== '_')
                                     $ liftM2 (&&) isLower isAscii)
                         prefix) of
         Nothing     -> Nothing
-        Just (c, _) -> Just $ TypeIDErrorPrefixInvalidChar prefix c
+        Just (c, _) -> Just $ TypeIDErrorPrefixInvalidChar prefixStr c
+  where
+    prefixStr = T.unpack prefix
 {-# INLINE checkPrefix #-}
 
 -- | Check if the prefix is valid and the suffix 'UUID' has the correct v7
