diff --git a/source/hedgehog/Main.hs b/source/hedgehog/Main.hs
--- a/source/hedgehog/Main.hs
+++ b/source/hedgehog/Main.hs
@@ -1001,6 +1001,11 @@
     let t = Typeable.Proxy :: Typeable.Proxy [OsString.OsChar]
     fromFrom s t genOsString
 
+  property "OsChar" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Char
+    let t = Typeable.Proxy :: Typeable.Proxy OsString.OsChar
+    tryFromFrom s t Gen.ascii
+
 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
@@ -1175,6 +1175,21 @@
 instance From.From OsString.OsString [OsString.OsChar] where
   from = OsString.unpack
 
+-- | Uses 'OsString.unsafeFromChar'. Fails when the 'Char' does not fit in an
+-- '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.
+instance TryFrom.TryFrom Char OsString.OsChar where
+  tryFrom =
+    Utility.maybeTryFrom $ \c ->
+      let oc = OsString.unsafeFromChar c
+       in if OsString.toChar oc == c then Just oc else Nothing
+
+-- | Uses 'OsString.toChar'. Total because every 'OsString.OsChar' is a valid
+-- Unicode code point.
+instance From.From OsString.OsChar Char where
+  from = OsString.toChar
+
 -- | Uses 'OsString.encodeUtf'.
 instance TryFrom.TryFrom String OsString.OsString where
   tryFrom =
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
@@ -1868,6 +1868,12 @@
         f (OsString.pack [OsString.unsafeFromChar 'a', OsString.unsafeFromChar 'b'])
           `shouldBe` [OsString.unsafeFromChar 'a', OsString.unsafeFromChar 'b']
 
+    describe "From OsChar Char" $ do
+      let f = Witch.from @OsString.OsChar @Char
+      it "works" $ do
+        f (OsString.unsafeFromChar 'a') `shouldBe` 'a'
+        f (OsString.unsafeFromChar '\xFF') `shouldBe` '\xFF'
+
     describe "From Text OsString" $ do
       let f = Witch.from @Text.Text @OsString.OsString
       it "works" $ do
@@ -2474,6 +2480,14 @@
       let f = Witch.from @String @Encoding.Utf32BL
       it "works" $ do
         f "a" `shouldBe` Tagged.Tagged (LazyByteString.pack [0x00, 0x00, 0x00, 0x61])
+
+    describe "TryFrom Char OsChar" $ do
+      let f = hush . Witch.tryFrom @Char @OsString.OsChar
+      it "works" $ do
+        f 'a' `shouldBe` Just (OsString.unsafeFromChar 'a')
+        f '\xFF' `shouldBe` Just (OsString.unsafeFromChar '\xFF')
+        -- Above @0xFFFF@, so it fails on both POSIX and Windows.
+        f '\x10000' `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.2.0
+version: 1.3.3.0
 synopsis: Convert values from one type into another.
 description: Witch converts values from one type into another.
 build-type: Simple
