diff --git a/source/hedgehog/Main.hs b/source/hedgehog/Main.hs
--- a/source/hedgehog/Main.hs
+++ b/source/hedgehog/Main.hs
@@ -1006,6 +1006,12 @@
     let t = Typeable.Proxy :: Typeable.Proxy OsString.OsChar
     tryFromFrom s t Gen.ascii
 
+  property "OsChar/Word" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Word
+    let t = Typeable.Proxy :: Typeable.Proxy OsString.OsChar
+    -- @0@ to @0xFF@ fits an 'OsString.OsChar' on both POSIX and Windows.
+    tryFromFrom s t . Gen.integral $ Range.linear 0 0xFF
+
 groupText :: H.Group
 groupText = group "Text" $ do
   property "LazyText" $ do
diff --git a/source/library/Witch/Instances.hs b/source/library/Witch/Instances.hs
--- a/source/library/Witch/Instances.hs
+++ b/source/library/Witch/Instances.hs
@@ -1179,6 +1179,13 @@
 -- 'OsString.OsChar', which holds one byte on POSIX (code points above @0xFF@)
 -- and two bytes on Windows (code points above @0xFFFF@). Guarded by a round
 -- trip through 'OsString.toChar', so it never silently truncates.
+--
+-- An 'OsString.OsChar' is a single code unit in a platform encoding, not a
+-- character; even the @os-string@ documentation notes it should perhaps have
+-- been named @OsWord@. Treating it as a 'Char' is usually a mistake, since a
+-- Unicode code point may span several code units. Prefer the
+-- @'TryFrom.TryFrom' 'Word' 'OsString.OsChar'@ instance, which makes the code
+-- unit explicit.
 instance TryFrom.TryFrom Char OsString.OsChar where
   tryFrom =
     Utility.maybeTryFrom $ \c ->
@@ -1187,8 +1194,35 @@
 
 -- | Uses 'OsString.toChar'. Total because every 'OsString.OsChar' is a valid
 -- Unicode code point.
+--
+-- Be wary of this conversion: an 'OsString.OsChar' is a single code unit in a
+-- platform encoding rather than a character, so reinterpreting it as a 'Char'
+-- produces a meaningful code point only for single-unit values. Prefer the
+-- @'From.From' 'OsString.OsChar' 'Word'@ instance, which exposes the code unit
+-- without pretending it is a character.
 instance From.From OsString.OsChar Char where
   from = OsString.toChar
+
+-- | Exposes the underlying code unit of an 'OsString.OsChar' as a 'Word'. Total
+-- because an 'OsString.OsChar' is a single code unit (one byte on POSIX, two on
+-- Windows), which always fits in a 'Word'.
+instance From.From OsString.OsChar Word where
+  from = fromIntegral . Char.ord . OsString.toChar
+
+-- | Builds an 'OsString.OsChar' code unit from a 'Word'. Fails when the 'Word'
+-- does not fit in an 'OsString.OsChar', which holds one byte on POSIX (values
+-- above @0xFF@) and two bytes on Windows (values above @0xFFFF@). Guarded by a
+-- round trip, so it never silently truncates.
+instance TryFrom.TryFrom Word OsString.OsChar where
+  tryFrom =
+    Utility.maybeTryFrom $ \w ->
+      if w > 0x10FFFF
+        then Nothing
+        else
+          let oc = OsString.unsafeFromChar (Char.chr (fromIntegral w))
+           in if fromIntegral (Char.ord (OsString.toChar oc)) == w
+                then Just oc
+                else Nothing
 
 -- | Uses 'OsString.encodeUtf'.
 instance TryFrom.TryFrom String OsString.OsString where
diff --git a/source/test-suite/Main.hs b/source/test-suite/Main.hs
--- a/source/test-suite/Main.hs
+++ b/source/test-suite/Main.hs
@@ -1874,6 +1874,12 @@
         f (OsString.unsafeFromChar 'a') `shouldBe` 'a'
         f (OsString.unsafeFromChar '\xFF') `shouldBe` '\xFF'
 
+    describe "From OsChar Word" $ do
+      let f = Witch.from @OsString.OsChar @Word
+      it "works" $ do
+        f (OsString.unsafeFromChar 'a') `shouldBe` 97
+        f (OsString.unsafeFromChar '\xFF') `shouldBe` 255
+
     describe "From Text OsString" $ do
       let f = Witch.from @Text.Text @OsString.OsString
       it "works" $ do
@@ -2488,6 +2494,14 @@
         f '\xFF' `shouldBe` Just (OsString.unsafeFromChar '\xFF')
         -- Above @0xFFFF@, so it fails on both POSIX and Windows.
         f '\x10000' `shouldBe` Nothing
+
+    describe "TryFrom Word OsChar" $ do
+      let f = hush . Witch.tryFrom @Word @OsString.OsChar
+      it "works" $ do
+        f 97 `shouldBe` Just (OsString.unsafeFromChar 'a')
+        f 255 `shouldBe` Just (OsString.unsafeFromChar '\xFF')
+        -- Above @0x10FFFF@, so it fails on both POSIX and Windows.
+        f 0x110000 `shouldBe` Nothing
 
     describe "TryFrom String OsString" $ do
       let f = hush . Witch.tryFrom @String @OsString.OsString
diff --git a/witch.cabal b/witch.cabal
--- a/witch.cabal
+++ b/witch.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name: witch
-version: 1.3.3.0
+version: 1.3.4.0
 synopsis: Convert values from one type into another.
 description: Witch converts values from one type into another.
 build-type: Simple
