diff --git a/clr-bindings.cabal b/clr-bindings.cabal
--- a/clr-bindings.cabal
+++ b/clr-bindings.cabal
@@ -1,12 +1,12 @@
 name:                clr-bindings
-version:             0.1.0.0
+version:             0.2.0
 synopsis:            Glue between clr-host and clr-typed
 description:         Please see README.md
 homepage:            https://gitlab.com/tim-m89/clr-haskell/tree/master/libs/clr-bindings
 license:             BSD3
 license-file:        LICENSE
 author:              Tim Matthews
-maintainer:          tim.matthews7@gmail.com
+maintainer:          pepeiborra@gmail.com
 copyright:           2017 Tim Matthews
 category:            Language, FFI, CLR, .NET
 build-type:          Simple
@@ -19,12 +19,14 @@
 library
   hs-source-dirs:      src
   exposed-modules:     Clr.Bindings
-                     , Clr.Bindings.Box
                      , Clr.Bindings.BStr
                      , Clr.Bindings.DynImports
-                     , Clr.Bindings.ImportGen
+                     , Clr.Bindings.Exception
                      , Clr.Bindings.IEnumerable
+                     , Clr.Bindings.ImportGen
                      , Clr.Bindings.Object
+                     , Clr.Bindings.Object.Internal
+                     , Clr.Bindings.WrapImports
   build-depends:       base >= 4.7 && < 5, clr-typed, clr-host, clr-marshal, text, template-haskell, pipes
   default-language:    Haskell2010
 
diff --git a/src/Clr/Bindings.hs b/src/Clr/Bindings.hs
--- a/src/Clr/Bindings.hs
+++ b/src/Clr/Bindings.hs
@@ -1,34 +1,21 @@
 module Clr.Bindings
-  ( module Clr.Bindings.Box
+  ( module Clr.Bindings.BStr
   , module Clr.Bindings.DynImports
-  , module Clr.Bindings.BStr
+  , module Clr.Bindings.Object
+  , module Clr.Bindings.WrapImports
   , BStr(..)
-  , saveDynamicAssembly
   ) where
 
 
-import Clr.Marshal
-
-import Clr.Host
 import Clr.Host.BStr
 
-import Clr.Bindings.Box
-import Clr.Bindings.DynImports
-import Clr.Marshal.Host
 import Clr.Bindings.BStr
+import Clr.Bindings.DynImports
 import Clr.Bindings.Object
+import Clr.Bindings.WrapImports
 
-import Data.Word
-import Foreign.Ptr
 
 
--- | 'saveDynamicAssembly' saves the assembly containing the dynamically-generated
---   wrapper stubs to disk (for debugging purposes).
-saveDynamicAssembly :: IO ()
-saveDynamicAssembly = unsafeGetPointerToMethod "SaveDynamicAssembly" >>=  makeSaveDynamicAssemblyDelegate
-
-type SaveDynamicAssemblyDelegate = IO ()
-foreign import ccall "dynamic" makeSaveDynamicAssemblyDelegate :: FunPtr SaveDynamicAssemblyDelegate -> SaveDynamicAssemblyDelegate
 
 
 
diff --git a/src/Clr/Bindings/BStr.hs b/src/Clr/Bindings/BStr.hs
--- a/src/Clr/Bindings/BStr.hs
+++ b/src/Clr/Bindings/BStr.hs
@@ -6,7 +6,6 @@
 import Clr
 import Clr.Bridge
 import Clr.Marshal
-import Clr.UnmarshalAs
 
 import Clr.Host.BStr
 
@@ -19,13 +18,4 @@
 
 
 type instance BridgeTypePrim (T "System.String" '[]) = BStr
-
---
--- NB: This next line specifies that all methods
--- returning a System.String, get the result
--- converted to a Text. This needs a bit of work,
--- but polymorphism in the return type is going
--- to make compilation a lot harder. TODO.
---
-type instance UnmarshalAs BStr = Text
 
diff --git a/src/Clr/Bindings/Box.hs b/src/Clr/Bindings/Box.hs
deleted file mode 100644
--- a/src/Clr/Bindings/Box.hs
+++ /dev/null
@@ -1,161 +0,0 @@
-{-# LANGUAGE TypeApplications, TypeSynonymInstances, MultiParamTypeClasses, FlexibleInstances #-}
-
-module Clr.Bindings.Box where
-
-import Clr
-import Clr.Marshal
-
-import Clr.Host.BStr
-
-import Clr.Marshal.Host
-import Clr.Bindings.BStr
-
-import Data.Int
-import Data.Text
-import Data.Text.Foreign
-import Data.Word
-import Foreign.Marshal.Alloc
-import Foreign.Ptr
-import Foreign.Storable
-
-
--- | @'getBoxStub' t@ returns a function pointer to a function that, when
---   called, returns a boxed object reference to the given type.
-getBoxStub :: String -> IO (FunPtr f)
-getBoxStub typeName = marshal typeName $ \typeName'-> do
-  stub <- getBoxStubRaw
-  return $ stub typeName'
-
-getBoxStubRaw :: IO (GetBoxStubDelegate a)
-getBoxStubRaw = unsafeGetPointerToMethod "GetBoxStub" >>= return . makeGetBoxStubDelegate
-
-type GetBoxStubDelegate a = BStr -> FunPtr a
-foreign import ccall "dynamic" makeGetBoxStubDelegate :: FunPtr (GetBoxStubDelegate a) -> GetBoxStubDelegate a
-
---
--- Text
---
-
-instance Marshal Text (ObjectID obj) where
-  marshal x f = marshal @Text @BStr x $ \ptr-> do
-    stub <- boxStringStub
-    obj <- stub ptr
-    f obj
-
-type BoxStringStub a = BStr -> IO (ObjectID a)
-foreign import ccall "dynamic" makeBoxStringStub :: FunPtr (BoxStringStub a) -> (BoxStringStub a)
-
-boxStringStub :: IO (BoxStringStub a)
-boxStringStub = getBoxStub "System.String" >>= return . makeBoxStringStub
-
---
--- String
---
-
-instance Marshal String (ObjectID a) where
-  marshal x f = marshal (pack x) f
-
---
--- Int8
---
-
-instance Marshal Int8 (ObjectID obj) where
-  marshal x f = boxInt8Stub >>= \stub-> stub x >>= f
-
-type BoxInt8Stub a = Int8 -> IO (ObjectID a)
-foreign import ccall "dynamic" makeBoxInt8Stub :: FunPtr (BoxInt8Stub a) -> (BoxInt8Stub a)
-
-boxInt8Stub :: IO (BoxInt8Stub a)
-boxInt8Stub = getBoxStub "System.SByte" >>= return . makeBoxInt8Stub
-
---
--- Word8
---
-
-instance Marshal Word8 (ObjectID obj) where
-  marshal x f = boxWord8Stub >>= \stub-> stub x >>= f
-
-type BoxWord8Stub a = Word8 -> IO (ObjectID a)
-foreign import ccall "dynamic" makeBoxWord8Stub :: FunPtr (BoxWord8Stub a) -> (BoxWord8Stub a)
-
-boxWord8Stub :: IO (BoxWord8Stub a)
-boxWord8Stub = getBoxStub "System.Byte" >>= return . makeBoxWord8Stub
-
---
--- Int16
---
-
-instance Marshal Int16 (ObjectID obj) where
-  marshal x f = boxInt16Stub >>= \stub-> stub x >>= f
-
-type BoxInt16Stub a = Int16 -> IO (ObjectID a)
-foreign import ccall "dynamic" makeBoxInt16Stub :: FunPtr (BoxInt16Stub a) -> (BoxInt16Stub a)
-
-boxInt16Stub :: IO (BoxInt16Stub a)
-boxInt16Stub = getBoxStub "System.Int16" >>= return . makeBoxInt16Stub
-
---
--- Word16
---
-
-instance Marshal Word16 (ObjectID obj) where
-  marshal x f = boxWord16Stub >>= \stub-> stub x >>= f
-
-type BoxWord16Stub a = Word16 -> IO (ObjectID a)
-foreign import ccall "dynamic" makeBoxWord16Stub :: FunPtr (BoxWord16Stub a) -> (BoxWord16Stub a)
-
-boxWord16Stub :: IO (BoxWord16Stub a)
-boxWord16Stub = getBoxStub "System.UInt16" >>= return . makeBoxWord16Stub
-
---
--- Int32
---
-
-instance Marshal Int32 (ObjectID obj) where
-  marshal x f = boxInt32Stub >>= \stub-> stub x >>= f
-
-type BoxInt32Stub a = Int32 -> IO (ObjectID a)
-foreign import ccall "dynamic" makeBoxInt32Stub :: FunPtr (BoxInt32Stub a) -> (BoxInt32Stub a)
-
-boxInt32Stub :: IO (BoxInt32Stub a)
-boxInt32Stub = getBoxStub "System.Int32" >>= return . makeBoxInt32Stub
-
---
--- Word32
---
-
-instance Marshal Word32 (ObjectID obj) where
-  marshal x f = boxWord32Stub >>= \stub-> stub x >>= f
-
-type BoxWord32Stub a = Word32 -> IO (ObjectID a)
-foreign import ccall "dynamic" makeBoxWord32Stub :: FunPtr (BoxWord32Stub a) -> (BoxWord32Stub a)
-
-boxWord32Stub :: IO (BoxWord32Stub a)
-boxWord32Stub = getBoxStub "System.UInt32" >>= return . makeBoxWord32Stub
-
---
--- Int64
---
-
-instance Marshal Int64 (ObjectID obj) where
-  marshal x f = boxInt64Stub >>= \stub-> stub x >>= f
-
-type BoxInt64Stub a = Int64 -> IO (ObjectID a)
-foreign import ccall "dynamic" makeBoxInt64Stub :: FunPtr (BoxInt64Stub a) -> (BoxInt64Stub a)
-
-boxInt64Stub :: IO (BoxInt64Stub a)
-boxInt64Stub = getBoxStub "System.Int64" >>= return . makeBoxInt64Stub
-
---
--- Word64
---
-
-instance Marshal Word64 (ObjectID obj) where
-  marshal x f = boxWord64Stub >>= \stub-> stub x >>= f
-
-type BoxWord64Stub a = Word64 -> IO (ObjectID a)
-foreign import ccall "dynamic" makeBoxWord64Stub :: FunPtr (BoxWord64Stub a) -> (BoxWord64Stub a)
-
-boxWord64Stub :: IO (BoxWord64Stub a)
-boxWord64Stub = getBoxStub "System.UInt64" >>= return . makeBoxWord64Stub
-
diff --git a/src/Clr/Bindings/DynImports.hs b/src/Clr/Bindings/DynImports.hs
--- a/src/Clr/Bindings/DynImports.hs
+++ b/src/Clr/Bindings/DynImports.hs
@@ -9,7 +9,8 @@
 import Clr.Property
 import Clr.TypeString
 
-import Clr.Marshal.Host
+import Clr.Host
+import Clr.Host.Method
 
 import Data.Kind
 import Foreign.Ptr
@@ -46,22 +47,22 @@
 -- which is specified by implementing a _DynImport_ class
 --
 class MethodDynImportI1 t m arg0 where
-  methodDynImportI1 :: DynamicImportType (BridgeType t -> IngoreUnitType (BridgeType arg0) (IO (BridgeTypeM (ResultTypeI1 t m arg0))))
+  methodDynImportI1 :: DynamicImportType (BridgeType t -> IngoreUnitType (BridgeType arg0) (IO (BridgeType (ResultTypeI1 t m arg0))))
 
 class MethodDynImportI2 t m arg0 arg1 where
-  methodDynImportI2 :: DynamicImportType (BridgeType t -> BridgeType arg0 -> BridgeType arg1 -> IO (BridgeTypeM (ResultTypeI2 t m arg0 arg1)))
+  methodDynImportI2 :: DynamicImportType (BridgeType t -> BridgeType arg0 -> BridgeType arg1 -> IO (BridgeType (ResultTypeI2 t m arg0 arg1)))
 
 class MethodDynImportI3 t m arg0 arg1 arg2 where
-  methodDynImportI3 :: DynamicImportType (BridgeType t -> BridgeType arg0 -> BridgeType arg1 -> BridgeType arg2 -> IO (BridgeTypeM (ResultTypeI3 t m arg0 arg1 arg2)))
+  methodDynImportI3 :: DynamicImportType (BridgeType t -> BridgeType arg0 -> BridgeType arg1 -> BridgeType arg2 -> IO (BridgeType (ResultTypeI3 t m arg0 arg1 arg2)))
 
 class MethodDynImportS1 t m arg0 where
-  methodDynImportS1 :: DynamicImportType (IngoreUnitType (BridgeType arg0) (IO (BridgeTypeM (ResultTypeS1 t m arg0))))
+  methodDynImportS1 :: DynamicImportType (IngoreUnitType (BridgeType arg0) (IO (BridgeType (ResultTypeS1 t m arg0))))
 
 class MethodDynImportS2 t m arg0 arg1 where
-  methodDynImportS2 :: DynamicImportType (BridgeType arg0 -> BridgeType arg1 -> IO (BridgeTypeM (ResultTypeS2 t m arg0 arg1)))
+  methodDynImportS2 :: DynamicImportType (BridgeType arg0 -> BridgeType arg1 -> IO (BridgeType (ResultTypeS2 t m arg0 arg1)))
 
 class MethodDynImportS3 t m arg0 arg1 arg2 where
-  methodDynImportS3 :: DynamicImportType (BridgeType arg0 -> BridgeType arg1 -> BridgeType arg2 -> IO (BridgeTypeM (ResultTypeS3 t m arg0 arg1 arg2)))
+  methodDynImportS3 :: DynamicImportType (BridgeType arg0 -> BridgeType arg1 -> BridgeType arg2 -> IO (BridgeType (ResultTypeS3 t m arg0 arg1 arg2)))
 
 class ConstructorDynImport1 t arg0 where
   constructorDynImport1 :: DynamicImportType (IngoreUnitType (BridgeType arg0) (IO (BridgeType t)))
@@ -94,12 +95,12 @@
          , TString arg0
          , MethodResultI1 t m arg0
          , MethodDynImportI1 t m arg0
-         , HandleUnit (IngoreUnitType (BridgeType arg0) (IO (BridgeTypeM (ResultTypeI1 t m arg0)))) (BridgeType arg0) (IO (BridgeTypeM (ResultTypeI1 t m arg0)))
+         , HandleUnit (IngoreUnitType (BridgeType arg0) (IO (BridgeType (ResultTypeI1 t m arg0)))) (BridgeType arg0) (IO (BridgeType (ResultTypeI1 t m arg0)))
          ) => MethodInvokeI1 t m arg0 where
   rawInvokeI1 obj x = do
     fp   <- getMethodStub (tString @t) (tString @m) (tString @arg0)
     let f = methodDynImportI1 @t @m @arg0 fp
-    handleUnit @(IngoreUnitType (BridgeType arg0) (IO (BridgeTypeM (ResultTypeI1 t m arg0)))) @(BridgeType arg0) @(IO (BridgeTypeM (ResultTypeI1 t m arg0))) (f obj) x
+    handleUnit @(IngoreUnitType (BridgeType arg0) (IO (BridgeType (ResultTypeI1 t m arg0)))) @(BridgeType arg0) @(IO (BridgeType (ResultTypeI1 t m arg0))) (f obj) x
 
 instance ( TString t
          , TString m
@@ -125,12 +126,12 @@
          , TString arg0
          , MethodResultS1 t m arg0
          , MethodDynImportS1 t m arg0
-         , HandleUnit (IngoreUnitType (BridgeType arg0) (IO (BridgeTypeM (ResultTypeS1 t m arg0)))) (BridgeType arg0) (IO (BridgeTypeM (ResultTypeS1 t m arg0)))
+         , HandleUnit (IngoreUnitType (BridgeType arg0) (IO (BridgeType (ResultTypeS1 t m arg0)))) (BridgeType arg0) (IO (BridgeType (ResultTypeS1 t m arg0)))
          ) => MethodInvokeS1 t m arg0 where
   rawInvokeS1 x = do
     fp   <- getMethodStub (tString @t) (tString @m) (tString @arg0)
     let f = methodDynImportS1 @t @m @arg0 fp
-    handleUnit @(IngoreUnitType (BridgeType arg0) (IO (BridgeTypeM (ResultTypeS1 t m arg0)))) @(BridgeType arg0) @(IO (BridgeTypeM (ResultTypeS1 t m arg0))) f x
+    handleUnit @(IngoreUnitType (BridgeType arg0) (IO (BridgeType (ResultTypeS1 t m arg0)))) @(BridgeType arg0) @(IO (BridgeType (ResultTypeS1 t m arg0))) f x
 
 instance ( TString t
          , TString m
diff --git a/src/Clr/Bindings/Exception.hs b/src/Clr/Bindings/Exception.hs
new file mode 100644
--- /dev/null
+++ b/src/Clr/Bindings/Exception.hs
@@ -0,0 +1,173 @@
+{-# LANGUAGE GADTs, DataKinds, KindSignatures, PolyKinds, TypeFamilies, TypeOperators, RankNTypes, MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleInstances, FlexibleContexts, ScopedTypeVariables, ExistentialQuantification #-}
+{-# LANGUAGE UndecidableInstances, TypeApplications, AllowAmbiguousTypes, TypeInType, TypeFamilyDependencies, FunctionalDependencies #-}
+
+module Clr.Bindings.Exception(catch) where
+
+import Clr
+import Clr.Bridge
+import Clr.Curry
+import Clr.Resolver
+import Clr.TypeString
+import Clr.Types
+
+import Clr.Bindings.BStr
+import Clr.Bindings.DynImports
+import Clr.Bindings.Object
+import Clr.Bindings.WrapImports
+
+import Clr.Host.BStr
+import Clr.Host.GCHandle
+
+import Clr.Marshal
+import Clr.MarshalF
+
+import Control.Concurrent
+import GHC.TypeLits
+import Data.Kind
+import Data.Typeable
+import Foreign.Ptr
+
+import Data.Text
+
+-- Synonyms to help prevent typos later on
+type T_Exception            = T "System.Exception" '[]
+type T_Driver               = T "Salsa.Driver" '[]
+type T_TryDelegate   a      = T "Salsa.TryDelegate" '[a]
+type T_CatchDelegate a ex   = T "Salsa.CatchDelegate" '[a, ex]
+type T_RunCatchHandler a ex = T "RunCatchHandler" '[a, ex]
+
+-- Only 1 overload candidate for RunCatchHandler
+type instance Candidates T_Driver (T_RunCatchHandler a ex) = '[ '[ T_TryDelegate a, T_CatchDelegate a ex] ]
+
+-- We have 2 delegate types, 1 for the try handler
+instance Delegate (T_TryDelegate a) where
+  type DelegateArgTypes   (T_TryDelegate a)      = '[]
+  type DelegateResultType (T_TryDelegate a)      = a
+
+-- And another for the catch handler
+instance Delegate (T_CatchDelegate a ex) where
+  type DelegateArgTypes   (T_CatchDelegate a ex) = '[ ex ]
+  type DelegateResultType (T_CatchDelegate a ex) = a
+
+-- Foreign imports for non primitive results
+foreign import ccall "wrapper" wrapTryDelegateObj      :: (IO (GCHandle a)) -> IO (FunPtr (IO (GCHandle a)))
+foreign import ccall "wrapper" wrapCatchDelegateObj    :: (GCHandle ex -> IO (GCHandle a)) -> IO (FunPtr (GCHandle ex -> IO (GCHandle a)))
+foreign import ccall "dynamic" makeRunCatchHandlerObj  :: FunPtr (GCHandle tryD -> GCHandle catchD -> IO (GCHandle a)) -> (GCHandle tryD -> GCHandle catchD -> IO (GCHandle a))
+
+-- Foreign imports for string results
+foreign import ccall "wrapper" wrapTryDelegateBStr     :: (IO BStr) -> IO (FunPtr (IO BStr))
+foreign import ccall "wrapper" wrapCatchDelegateBStr   :: (GCHandle ex -> IO BStr) -> IO (FunPtr (GCHandle ex -> IO BStr))
+foreign import ccall "dynamic" makeRunCatchHandlerBStr :: FunPtr (GCHandle tryD -> GCHandle catchD -> IO BStr) -> (GCHandle tryD -> GCHandle catchD -> IO BStr)
+
+-- TODO: foreign imports for other prims
+
+-- Run catch handler is a static method of 2 args with this result type
+instance MethodResultS2 T_Driver (T_RunCatchHandler a ex) (T_TryDelegate a) (T_CatchDelegate a ex) where
+  type ResultTypeS2 T_Driver (T_RunCatchHandler a ex) (T_TryDelegate a) (T_CatchDelegate a ex) = a
+
+-- Wrapper / Dyn import mappings for object result type
+instance {-# OVERLAPS #-} (IsPrimType a ~ 'False, BridgeType a ~ GCHandle a) => WrapperImport (T_TryDelegate a) where
+  wrapperImport = wrapTryDelegateObj
+instance {-# OVERLAPS #-} (IsPrimType a ~ 'False, BridgeType a ~ GCHandle a, BridgeType ex ~ GCHandle ex) => WrapperImport (T_CatchDelegate a ex) where
+  wrapperImport = wrapCatchDelegateObj
+instance {-# OVERLAPS #-} (IsPrimType a ~ 'False, BridgeType a ~ GCHandle a) => MethodDynImportS2 T_Driver (T_RunCatchHandler a ex) (T_TryDelegate a) (T_CatchDelegate a ex) where
+  methodDynImportS2 = makeRunCatchHandlerObj
+
+-- Wrapper / Dyn import mappings for string result type
+instance {-# OVERLAPS #-} WrapperImport (T_TryDelegate T_string) where
+  wrapperImport = wrapTryDelegateBStr
+instance {-# OVERLAPS #-} (BridgeType ex ~ GCHandle ex) => WrapperImport (T_CatchDelegate T_string ex) where
+  wrapperImport = wrapCatchDelegateBStr
+instance {-# OVERLAPS #-} MethodDynImportS2 T_Driver (T_RunCatchHandler T_string ex) (T_TryDelegate T_string) (T_CatchDelegate T_string ex) where
+  methodDynImportS2 = makeRunCatchHandlerBStr
+
+-- TODO: Wrapper / Dyn import mappings for other prims
+
+-- The function that is exported
+catch :: forall haskResult t_dTry t_dCatch t_handler t_ex t_args t_result b_try b_catch b_result .
+          -- Types we know the most about
+          ( t_ex `Implements` T_Exception ~ 'True
+          , t_dTry    ~ (T_TryDelegate   t_result)
+          , t_dCatch  ~ (T_CatchDelegate t_result t_ex)
+          , t_handler ~ (T_RunCatchHandler t_result t_ex)
+          -- Common contraints between types
+          , IsPrimType t_ex ~ 'False
+          , BridgeType t_ex ~ GCHandle t_ex
+          , TString t_result
+          , TString t_ex
+          , t_result ~ HaskToClr haskResult
+          , BridgeType t_result ~ b_result
+          , Unmarshal haskResult b_result
+          , Unmarshal b_result haskResult
+          -- Constraints for the try delegate
+          , t_dTry ~ (T_TryDelegate t_result)
+          , Delegate t_dTry
+          , DelegateArity t_dTry ~ 0
+          , DelegateConstructorN 0 t_dTry
+          , DelegateBridgeType t_dTry ~ b_try
+          , DelegateResultType t_dTry ~ t_result
+          , MarshalF 0 (IO haskResult) b_try
+          -- Constraints for the catch delegate
+          , t_dCatch ~ (T_CatchDelegate t_result t_ex)
+          , Delegate t_dCatch
+          , DelegateArity t_dCatch ~ 1
+          , DelegateConstructorN 1 t_dCatch
+          , DelegateBridgeType t_dCatch ~ b_catch
+          , DelegateResultType t_dCatch ~ t_result
+          , MarshalF 1 (Object t_ex -> IO haskResult) b_catch
+          -- Constraints for the RunCatchHandler static method
+          , t_args ~ '[ t_dTry, t_dCatch ]
+          , ResolveMember t_args (Candidates T_Driver t_handler) ~ t_args
+          , MethodS 2 T_Driver t_handler t_args
+          ) => IO haskResult -> (Object t_ex -> IO haskResult) -> IO haskResult
+catch tryF catchF = do
+  tryD   <- makeTryDelegate tryF
+  catchD <- makeCatchDelegate catchF
+  runCatchHandler (tryD, catchD)
+
+-- How to build a try delegate
+makeTryDelegate :: forall t_dTry b_try t_result haskResult .
+                    ( t_dTry ~ (T_TryDelegate t_result)
+                    , Delegate t_dTry
+                    , DelegateArity t_dTry ~ 0
+                    , DelegateConstructorN 0 t_dTry
+                    , DelegateBridgeType t_dTry ~ b_try
+                    , DelegateResultType t_dTry ~ t_result
+                    , MarshalF 0 (IO haskResult) b_try
+                    , TString t_result
+                    ) => IO haskResult -> IO (Object (T_TryDelegate t_result))
+makeTryDelegate f = delegate @t_dTry f
+
+-- How to build a catch delegate
+makeCatchDelegate :: forall t_dCatch b_catch t_result haskResult t_ex .
+                    ( t_ex `Implements` T_Exception ~ 'True
+                    , t_dCatch ~ (T_CatchDelegate t_result t_ex)
+                    , Delegate t_dCatch
+                    , DelegateArity t_dCatch ~ 1
+                    , DelegateConstructorN 1 t_dCatch
+                    , DelegateBridgeType t_dCatch ~ b_catch
+                    , DelegateResultType t_dCatch ~ t_result
+                    , MarshalF 1 (Object t_ex -> IO haskResult) b_catch
+                    , TString t_result
+                    , TString t_ex
+                    , IsPrimType t_ex ~ 'False
+                    , BridgeType t_ex ~ GCHandle t_ex
+                    , t_result ~ HaskToClr haskResult
+                    , Unmarshal haskResult (BridgeType t_result)
+                    ) => (Object t_ex -> IO haskResult) -> IO (Object (T_CatchDelegate t_result t_ex))
+makeCatchDelegate f = delegate @t_dCatch f
+
+-- The static method called to run this
+runCatchHandler :: forall b_result haskResult t_result t_ex t_args t_dTry t_dCatch t_handler .
+                    ( t_ex `Implements` T_Exception ~ 'True
+                    , t_dTry    ~ (T_TryDelegate   t_result)
+                    , t_dCatch  ~ (T_CatchDelegate t_result t_ex)
+                    , t_handler ~ (T_RunCatchHandler t_result t_ex)
+                    , t_args ~ '[ t_dTry, t_dCatch ]
+                    , ResolveMember t_args (Candidates T_Driver t_handler) ~ t_args
+                    , MethodS 2 T_Driver t_handler t_args
+                    , BridgeType t_result ~ b_result
+                    , Unmarshal b_result haskResult
+                    ) => (Object (T_TryDelegate t_result), Object (T_CatchDelegate t_result t_ex))  -> IO haskResult
+runCatchHandler (tryDel, catchDel) = invokeS @t_handler @T_Driver @b_result @haskResult (tryDel, catchDel)
diff --git a/src/Clr/Bindings/IEnumerable.hs b/src/Clr/Bindings/IEnumerable.hs
--- a/src/Clr/Bindings/IEnumerable.hs
+++ b/src/Clr/Bindings/IEnumerable.hs
@@ -7,16 +7,18 @@
 
 import Clr
 import Clr.Bridge
-import Clr.Marshal
-import Clr.Marshal.Host
-import Clr.UnmarshalAs
+import Clr.Resolver
 import Clr.TypeString
 
+import Clr.Marshal
+
 import Clr.Host
 import Clr.Host.BStr
+import Clr.Host.GCHandle
 
 import Clr.Bindings.BStr
 import Clr.Bindings.DynImports
+import Clr.Bindings.Object
 
 import Data.Kind
 import Data.Type.Bool
@@ -46,22 +48,22 @@
 type instance SuperTypes (T_IEnumerable t) = '[ T_IEnumerable', T_object ]
 type instance SuperTypes (T_IEnumerator t) = '[ T_IEnumerator', T_object ]
 
-foreign import ccall "dynamic" makeGetEnumerator      :: FunPtr (ObjectID a -> IO (ObjectID b)) -> (ObjectID a -> IO (ObjectID b))
-foreign import ccall "dynamic" makeEnumeratorMoveNext :: FunPtr (ObjectID (T_IEnumerator') -> IO Bool) -> (ObjectID (T_IEnumerator') -> IO Bool)
+foreign import ccall "dynamic" makeGetEnumerator      :: FunPtr (GCHandle a -> IO (GCHandle b)) -> (GCHandle a -> IO (GCHandle b))
+foreign import ccall "dynamic" makeEnumeratorMoveNext :: FunPtr (GCHandle (T_IEnumerator') -> IO Bool) -> (GCHandle (T_IEnumerator') -> IO Bool)
 
-foreign import ccall "dynamic" makeEnumeratorCurrentBStr  :: FunPtr (ObjectID (T_IEnumerator elem) -> IO BStr) -> (ObjectID (T_IEnumerator elem) -> IO BStr)
-foreign import ccall "dynamic" makeEnumeratorCurrentBool  :: FunPtr (ObjectID (T_IEnumerator elem) -> IO Bool) -> (ObjectID (T_IEnumerator elem) -> IO Bool)
+foreign import ccall "dynamic" makeEnumeratorCurrentBStr  :: FunPtr (GCHandle (T_IEnumerator elem) -> IO BStr) -> (GCHandle (T_IEnumerator elem) -> IO BStr)
+foreign import ccall "dynamic" makeEnumeratorCurrentBool  :: FunPtr (GCHandle (T_IEnumerator elem) -> IO Bool) -> (GCHandle (T_IEnumerator elem) -> IO Bool)
 -- TODO: makeEnumCurrent_ for every other prim type
-foreign import ccall "dynamic" makeEnumeratorCurrentObj   :: FunPtr (ObjectID (T_IEnumerator elem) -> IO (ObjectID elem)) -> (ObjectID (T_IEnumerator elem) -> IO (ObjectID elem))
+foreign import ccall "dynamic" makeEnumeratorCurrentObj   :: FunPtr (GCHandle (T_IEnumerator elem) -> IO (GCHandle elem)) -> (GCHandle (T_IEnumerator elem) -> IO (GCHandle elem))
 
 instance MethodResultI1 (T_IEnumerable t) (T_GetEnumerator) () where
-  type ResultTypeI1 (T_IEnumerable t) (T_GetEnumerator) () = 'Just (T_IEnumerator t)
+  type ResultTypeI1 (T_IEnumerable t) (T_GetEnumerator) () = (T_IEnumerator t)
 
 instance MethodDynImportI1 (T_IEnumerable t) (T_GetEnumerator) () where
   methodDynImportI1 = makeGetEnumerator
 
 instance MethodResultI1 T_IEnumerator' T_MoveNext () where
-  type ResultTypeI1 T_IEnumerator' T_MoveNext () = 'Just T_bool
+  type ResultTypeI1 T_IEnumerator' T_MoveNext () = T_bool
 
 instance MethodDynImportI1 T_IEnumerator' T_MoveNext () where
   methodDynImportI1 = makeEnumeratorMoveNext
@@ -97,7 +99,6 @@
 ienumCurrent :: forall elem propertyBridge propertyHask .
   ( PropertyGetI (T_IEnumerator elem) T_Current
   , BridgeType (PropertyTypeI (T_IEnumerator elem) T_Current) ~ propertyBridge
-  , UnmarshalAs propertyBridge ~ propertyHask
   , Unmarshal propertyBridge propertyHask
   ) => Object (T_IEnumerator elem) -> IO propertyHask
 ienumCurrent ienum = getPropI @T_Current ienum
@@ -111,7 +112,6 @@
   , TString elem
   , PropertyGetI (T_IEnumerator elem) T_Current
   , BridgeType (PropertyTypeI (T_IEnumerator elem) T_Current) ~ elemBridge
-  , UnmarshalAs elemBridge ~ elemHask
   , Unmarshal elemBridge elemHask
   ) => Object t -> Producer elemHask IO ()
 toProducer ienumerable = do
@@ -121,7 +121,6 @@
 toProducer' :: forall elem elemBridge elemHask .
   ( PropertyGetI (T_IEnumerator elem) T_Current
   , BridgeType (PropertyTypeI (T_IEnumerator elem) T_Current) ~ elemBridge
-  , UnmarshalAs elemBridge ~ elemHask
   , Unmarshal elemBridge elemHask
   ) => Object (T_IEnumerator elem) -> Producer elemHask IO ()
 toProducer' ienumerator = do
@@ -138,7 +137,6 @@
   , TString elem
   , PropertyGetI (T_IEnumerator elem) T_Current
   , BridgeType (PropertyTypeI (T_IEnumerator elem) T_Current) ~ elemBridge
-  , UnmarshalAs elemBridge ~ elemHask
   , Unmarshal elemBridge elemHask
   ) => Object t -> IO [elemHask]
 toListM ienumerable = Pipes.Prelude.toListM $ toProducer ienumerable
diff --git a/src/Clr/Bindings/Object.hs b/src/Clr/Bindings/Object.hs
--- a/src/Clr/Bindings/Object.hs
+++ b/src/Clr/Bindings/Object.hs
@@ -1,41 +1,58 @@
-{-# LANGUAGE TypeInType, TypeApplications, TypeSynonymInstances, MultiParamTypeClasses, FlexibleInstances, TypeFamilies #-}
+{-# LANGUAGE TypeInType, TypeApplications, TypeSynonymInstances, MultiParamTypeClasses, FlexibleInstances, TypeFamilies, TypeOperators, ScopedTypeVariables, AllowAmbiguousTypes #-}
 
-module Clr.Bindings.Object where
+module Clr.Bindings.Object
+ ( objectToString
+ , objectGetType
+ , downCast
+ ) where
 
 import Clr
 import Clr.TypeString
 
+import Clr.Marshal
+
 import Clr.Host
 import Clr.Host.BStr
+import Clr.Host.GCHandle
 
 import Clr.Bindings.DynImports
-import Clr.Marshal.Host
 import Clr.Bindings.BStr
-
-import Foreign.Ptr
-
-
-type T_ToString = T "ToString" '[]
-
-type instance SuperTypes T_object = '[ ]
-
-type instance Members T_object = '[ T_ToString, T "GetType" '[] ]
-
-type instance Candidates T_object  T_ToString       = '[ '[ ] ]
-type instance Candidates T_object (T "GetType" '[]) = '[ '[ ] ]
+import Clr.Bindings.Object.Internal
 
-foreign import ccall "dynamic" makeToString :: FunPtr (ObjectID t -> IO BStr) -> (ObjectID t -> IO BStr)
-foreign import ccall "dynamic" makeGetType  :: FunPtr (ObjectID t -> IO (ObjectID (T "System.Type" '[]))) -> (ObjectID t -> IO (ObjectID (T "System.Type" '[])))
+import Data.Text as T
 
-instance MethodResultI1 T_object T_ToString () where
-  type ResultTypeI1 T_object T_ToString () = 'Just T_string
+--
+-- System.Object.ToString()
+--
+objectToString :: (t  `Implements` T_object ~ 'True) => Object t -> IO T.Text
+objectToString o = do
+  let o' = upCast o :: Object T_object
+  invokeI @T_ToString o' ()
 
-instance MethodResultI1 T_object (T "GetType" '[]) () where
-  type ResultTypeI1 T_object (T "GetType" '[]) () = 'Just (T "System.Type" '[])
+--
+-- System.Object.GetType()
+--
+objectGetType :: (t  `Implements` T_object ~ 'True) => Object t -> IO (Object T_Type)
+objectGetType o = do
+  let o' = upCast o :: Object T_object
+  invokeI @T_GetType o' ()
 
-instance MethodDynImportI1 T_object T_ToString () where
-  methodDynImportI1 = makeToString
+--
+-- `downCast @typ o` is `Just o` casted to typ if possible, otherwise Nothing
+--
+downCast :: forall ts t t' .
+ ( MakeT ts ~ t'                           -- Shorthand to long notation conversion
+ , TString t'                              -- And the result of the above can be turned into a runtime string
+ , t  `Implements` T_object ~ 'True        -- Supplied object must at least inherit from Object so we can call Object.GetType
+ , t' `Implements` t ~ 'True               -- Ensure the desired cast is not something meaningless like cat -> dog at compile time
+ ) => Object t -> IO (Maybe (Object t'))
+downCast o = do
+  typ  <- objectGetType o
+  typ' <- typeGetType (T.pack (tString @t'))
+  canDownCast <- typ' `typeIsAssignableFrom` typ
+  if canDownCast then
+    return $ Just $ unsafeDownCast o
+  else
+    return Nothing
 
-instance MethodDynImportI1 T_object (T "GetType" '[]) () where
-  methodDynImportI1 = makeGetType
 
diff --git a/src/Clr/Bindings/Object/Internal.hs b/src/Clr/Bindings/Object/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Clr/Bindings/Object/Internal.hs
@@ -0,0 +1,150 @@
+{-# LANGUAGE TypeInType, TypeApplications, TypeSynonymInstances, MultiParamTypeClasses, FlexibleInstances, TypeFamilies #-}
+
+module Clr.Bindings.Object.Internal
+  ( typeGetType
+  , typeIsAssignableFrom
+  , T_Type
+  , T_ToString
+  , T_GetType
+  ) where
+
+import Clr
+import Clr.Bridge
+import Clr.Resolver
+import Clr.TypeString
+
+import Clr.Marshal
+
+import Clr.Host
+import Clr.Host.BStr
+import Clr.Host.GCHandle
+
+import Clr.Bindings.DynImports
+import Clr.Bindings.BStr
+
+import Data.Coerce
+import Foreign.Ptr
+import Foreign.ForeignPtr
+
+import Data.Text as T
+
+--
+-- Synonyms for other types referenced here
+--
+type T_Type = T "System.Type" '[]
+
+--
+-- Object methods
+--
+type T_Equals              = T "Equals" '[]
+type T_Finalize            = T "Finalize" '[]
+type T_GetHashCode         = T "GetHashCode" '[]
+type T_MemberwiseClone     = T "MemberwiseClone" '[]
+type ReferenceEquals       = T "ReferenceEquals" '[]
+type T_ToString            = T "ToString" '[]
+
+--
+-- Type members
+--
+type T_FullName            = T "FullName" '[]
+type T_GetGenericArguments = T "GetGenericArguments" '[]
+type T_GetMembers          = T "GetMembers" '[]
+type T_IsAssignableFrom    = T "IsAssignableFrom" '[]
+type T_Namespace           = T "Namespace" '[]
+
+-- Members that share the same name on both Object & Type
+type T_GetType             = T "GetType"  '[]
+
+type instance SuperTypes T_object = '[ ]
+
+--
+-- Member instance declarations. Only are few are used internally, but the others must be declared also
+-- as Haskell always exports & imports instances. The import generator must then skip over these.
+--
+type instance Members T_object = '[ T_ToString, T_GetType ]
+
+-- Doesn't yet conver all members of System.Type. TODO
+type instance Members T_Type   = '[ T_FullName
+                                  , T_GetGenericArguments
+                                  , T_GetMembers
+                                  , T_GetType
+                                  , T_IsAssignableFrom
+                                  , T_Namespace              ]
+
+type instance Candidates T_object T_ToString          = '[ '[ ] ]
+type instance Candidates T_object T_GetType           = '[ '[ ] ]
+type instance Candidates T_Type   T_GetType           = '[ '[ T_string ] ]
+type instance Candidates T_Type   T_IsAssignableFrom  = '[ '[ T_Type ] ]
+
+foreign import ccall "dynamic" makeObjToString          :: FunPtr (GCHandle t -> IO BStr) -> (GCHandle t -> IO BStr)
+foreign import ccall "dynamic" makeObjGetType           :: FunPtr (GCHandle t -> IO (GCHandle (T "System.Type" '[]))) -> (GCHandle t -> IO (GCHandle (T "System.Type" '[])))
+foreign import ccall "dynamic" makeTypeGetType          :: FunPtr (BStr -> IO (GCHandle T_Type)) -> (BStr -> IO (GCHandle T_Type))
+foreign import ccall "dynamic" makeTypeIsAssignableFrom :: FunPtr (GCHandle T_Type -> GCHandle T_Type -> IO Bool) -> (GCHandle T_Type -> GCHandle T_Type -> IO Bool)
+
+instance MethodResultI1 T_object T_ToString () where
+  type ResultTypeI1 T_object T_ToString () = T_string
+
+instance MethodResultI1 T_object T_GetType () where
+  type ResultTypeI1 T_object T_GetType () = T_Type
+
+instance MethodResultS1 T_Type T_GetType T_string where
+  type ResultTypeS1 T_Type T_GetType T_string = T_Type
+
+instance MethodResultI1 T_Type T_IsAssignableFrom T_Type where
+  type ResultTypeI1 T_Type T_IsAssignableFrom T_Type = T_bool
+
+instance MethodDynImportI1 T_object T_ToString () where
+  methodDynImportI1 = makeObjToString
+
+instance MethodDynImportI1 T_object T_GetType () where
+  methodDynImportI1 = makeObjGetType
+
+instance MethodDynImportS1 T_Type T_GetType T_string where
+  methodDynImportS1 = makeTypeGetType
+
+instance MethodDynImportI1 T_Type T_IsAssignableFrom T_Type where
+  methodDynImportI1 = makeTypeIsAssignableFrom
+
+--
+-- System.Type.GetType(System.String)
+--
+typeGetType :: T.Text -> IO (Object T_Type)
+typeGetType = invokeS @T_GetType @T_Type
+
+--
+-- System.Type.IsAssignableFrom(System.Type)
+--
+typeIsAssignableFrom :: Object T_Type -> Object T_Type -> IO (Bool)
+typeIsAssignableFrom t1 t2 = invokeI @T_IsAssignableFrom t1 t2
+
+--
+-- Marshaling Object <-> GCHandle
+--
+
+-- clr-typed doesn't know of GCHandle as it is provided by clr-host
+type instance BridgeTypeObject t = GCHandle t
+
+-- Calling a CLR function from Haskell
+instance {-# OVERLAPS #-} Marshal (Object t) (GCHandle t) where
+  marshal (Object x) f = withForeignPtr x $ \x'-> f $ coerce x'
+
+-- Calling a Haskell function from the CLR
+instance {-# OVERLAPS #-} (TString t) => Marshal (GCHandle t) (Object t) where
+  marshal x f = do
+    x' <- newHandle x
+    finalizer <- gcHandleFinalizer
+    fp <- newForeignPtr finalizer (coerce x')
+    f $ Object fp
+
+-- Returning from a CLR function that was called from Haskell
+instance {-# OVERLAPPING #-} (TString t) => Unmarshal (GCHandle t) (Object t) where
+  unmarshal x = do
+    finalizer <- gcHandleFinalizer
+    fp <- newForeignPtr finalizer (coerce x)
+    return $ Object fp
+
+-- Returning from a Haskell function that was called by the CLR
+instance {-# OVERLAPPING #-} (TString t) => Unmarshal (Object t) (GCHandle t) where
+  unmarshal (Object x) = withForeignPtr x $ \x'-> newHandle $ coerce x'
+
+
diff --git a/src/Clr/Bindings/WrapImports.hs b/src/Clr/Bindings/WrapImports.hs
new file mode 100644
--- /dev/null
+++ b/src/Clr/Bindings/WrapImports.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE TypeInType, FlexibleInstances, MultiParamTypeClasses, TypeFamilies, TypeApplications, ScopedTypeVariables, AllowAmbiguousTypes, UndecidableInstances #-}
+
+module Clr.Bindings.WrapImports where
+
+import Clr.Object
+import Clr.Bridge
+import Clr.Delegate
+import Clr.TypeString
+
+import Clr.Host
+import Clr.Host.BStr
+import Clr.Host.GCHandle
+import Clr.Host.Delegate
+
+import Clr.Marshal
+
+import Data.Kind
+import Foreign.Ptr
+
+--
+-- WrapperImportType t is the type of a function from a `t` to a `FunPtr t`
+--
+type WrapperImportType t = t -> IO (FunPtr t)
+
+class WrapperImport t where
+  wrapperImport :: WrapperImportType (DelegateBridgeType t)
+
+instance ( TString t
+         , Delegate t
+         , BridgeType t ~ GCHandle t
+         , DelegateArgTypes t ~ '[]
+         , WrapperImport t
+         ) => DelegateConstructor0 t where
+  rawConstructDelegate0 f = do
+    delCtor <- getDelegateConstructorStub (tString @t) (wrapperImport @t)
+    delCtor f
+
+instance ( TString t
+         , Delegate t
+         , BridgeType t ~ GCHandle t
+         , DelegateArgTypes t ~ '[ a0 ]
+         , WrapperImport t
+         ) => DelegateConstructor1 t where
+  rawConstructDelegate1 f = do
+    delCtor <- getDelegateConstructorStub (tString @t) (wrapperImport @t)
+    delCtor f
+
+instance ( TString t
+         , Delegate t
+         , BridgeType t ~ GCHandle t
+         , DelegateArgTypes t ~ '[ a0, a1 ]
+         , WrapperImport t
+         ) => DelegateConstructor2 t where
+  rawConstructDelegate2 f = do
+    delCtor <- getDelegateConstructorStub (tString @t) (wrapperImport @t)
+    delCtor f
+
+
