diff --git a/Data/GI/Base/Attributes.hs b/Data/GI/Base/Attributes.hs
--- a/Data/GI/Base/Attributes.hs
+++ b/Data/GI/Base/Attributes.hs
@@ -106,7 +106,7 @@
 -- `set` afterwards. That these invariants hold is also checked during
 -- compile time.
 --
--- == Nullable atributes
+-- == Nullable attributes
 --
 -- Whenever the attribute is represented as a pointer in the C side,
 -- it is often the case that the underlying C representation admits or
@@ -115,7 +115,7 @@
 -- representing the @NULL@ pointer value (notable exceptions are
 -- `Data.GI.Base.BasicTypes.GList` and
 -- `Data.GI.Base.BasicTypes.GSList`, for which @NULL@ is represented
--- simply as he empty list). This can be overriden in the
+-- simply as the empty list). This can be overridden in the
 -- introspection data, since sometimes attributes are non-nullable,
 -- even if the type would allow for @NULL@.
 --
diff --git a/Data/GI/Base/BasicConversions.hsc b/Data/GI/Base/BasicConversions.hsc
--- a/Data/GI/Base/BasicConversions.hsc
+++ b/Data/GI/Base/BasicConversions.hsc
@@ -201,7 +201,7 @@
   dataPtr <- peek (castPtr array :: Ptr (Ptr (Ptr a)))
   nitems <- peek (array `plusPtr` sizeOf dataPtr)
   go dataPtr nitems
-    where go :: Ptr (Ptr a) -> Int -> IO [Ptr a]
+    where go :: Ptr (Ptr a) -> CUInt -> IO [Ptr a]
           go _ 0 = return []
           go ptr n = do
             x <- peek ptr
@@ -558,7 +558,7 @@
             buf <- g_memdup ptr (fromIntegral size)
             (buf :) <$> go size (n-1) (ptr `plusPtr` size)
 
-unpackBoxedArrayWithLength :: forall a b. (Integral a, BoxedObject b) =>
+unpackBoxedArrayWithLength :: forall a b. (Integral a, GBoxed b) =>
                               Int -> a -> Ptr b -> IO [Ptr b]
 unpackBoxedArrayWithLength size n ptr = go size (fromIntegral n) ptr
     where go       :: Int -> Int -> Ptr b -> IO [Ptr b]
diff --git a/Data/GI/Base/BasicTypes.hsc b/Data/GI/Base/BasicTypes.hsc
--- a/Data/GI/Base/BasicTypes.hsc
+++ b/Data/GI/Base/BasicTypes.hsc
@@ -1,26 +1,28 @@
 {-# LANGUAGE ConstraintKinds, FlexibleContexts, FlexibleInstances,
-  DeriveDataTypeable, TypeFamilies, ScopedTypeVariables #-}
-{-# LANGUAGE DataKinds, TypeOperators, UndecidableInstances #-}
-{-# LANGUAGE AllowAmbiguousTypes #-}
+  DeriveDataTypeable, TypeFamilies, ScopedTypeVariables,
+  MultiParamTypeClasses, DataKinds, TypeOperators, UndecidableInstances,
+  AllowAmbiguousTypes #-}
 
 -- | Basic types used in the bindings.
 module Data.GI.Base.BasicTypes
     (
      -- * Memory management
       ManagedPtr(..)
-    , ManagedPtrNewtype
-    , BoxedObject(..)
-    , BoxedEnum(..)
-    , BoxedFlags(..)
-    , WrappedPtr(..)
+    , ManagedPtrNewtype(..)
+    , BoxedPtr(..)
+    , CallocPtr(..)
     , UnexpectedNullPointerReturn(..)
 
     -- * Basic GLib \/ GObject types
-    , GObject(..)
+    , TypedObject(..)
+    , GObject
     , GType(..)
     , CGType
     , gtypeName
     , GVariant(..)
+    , GBoxed
+    , BoxedEnum
+    , BoxedFlags
     , GParamSpec(..)
     , noGParamSpec
 
@@ -41,9 +43,8 @@
 
 import Control.Exception (Exception)
 
-import Data.Coerce (Coercible)
+import Data.Coerce (coerce, Coercible)
 import Data.IORef (IORef)
-import Data.Proxy (Proxy)
 import qualified Data.Text as T
 import Data.Typeable (Typeable)
 import Data.Word
@@ -73,47 +74,66 @@
 instance Eq (ManagedPtr a) where
   a == b = managedForeignPtr a == managedForeignPtr b
 
--- | A constraint ensuring that the given type is coercible to a
--- ManagedPtr. It will hold for newtypes of the form
---
--- > newtype Foo = Foo (ManagedPtr Foo)
---
--- which is the typical shape of wrapped 'GObject's.
-type ManagedPtrNewtype a = Coercible a (ManagedPtr ())
--- Notice that the Coercible here is to ManagedPtr (), instead of
+-- | A constraint ensuring that the given type is a newtype over a
+-- `ManagedPtr`.
+class Coercible a (ManagedPtr ()) => ManagedPtrNewtype a where
+  toManagedPtr :: a -> ManagedPtr a
+
+-- | A default instance for `IsManagedPtr` for newtypes over `ManagedPtr`.
+instance {-# OVERLAPPABLE #-} Coercible a (ManagedPtr ()) => ManagedPtrNewtype a where
+  toManagedPtr = coerce
+-- Notice that the Coercible here above to ManagedPtr (), instead of
 -- "ManagedPtr a", which would be the most natural thing. Both are
 -- representationally equivalent, so this is not a big deal. This is
 -- to work around a problem in ghc 7.10:
 -- https://ghc.haskell.org/trac/ghc/ticket/10715
+--
+-- Additionally, a simpler approach would be to simply do
+--
+-- > type IsManagedPtr a = Coercible a (ManagedPtr ())
+--
+-- but this requires the constructor of the datatype to be in scope,
+-- which is cumbersome (for instance, one often wants to call `castTo`
+-- on the results of `Gtk.builderGetObject`, which is a `GObject`,
+-- whose constructor is not necessarily in scope when using `GI.Gtk`).
+--
+-- When we make the bindings we will always add explicit instances,
+-- which cannot be hidden, avoiding the issue. We keep the default
+-- instance for convenience when writing new object types.
 
--- | Wrapped boxed structures, identified by their `GType`.
-class ManagedPtrNewtype a => BoxedObject a where
-    boxedType :: a -> IO GType -- This should not use the value of its
-                               -- argument.
+-- | Pointers to chunks of memory which we know how to copy and
+-- release.
+class ManagedPtrNewtype a => BoxedPtr a where
+  -- | Make a copy of the given `BoxedPtr`.
+  boxedPtrCopy   :: a -> IO a
+  -- | A pointer to a function for freeing the given pointer.
+  boxedPtrFree   :: a -> IO ()
 
--- | Enums with an associated `GType`.
-class BoxedEnum a where
-    boxedEnumType :: a -> IO GType
+-- | A ptr to a memory block which we know how to allocate and fill
+-- with zero.
+class BoxedPtr a => CallocPtr a where
+  -- | Allocate a zero-initialized block of memory for the given type.
+  boxedPtrCalloc :: IO (Ptr a)
 
--- | Flags with an associated `GType`.
-class BoxedFlags a where
-    boxedFlagsType :: Proxy a -> IO GType
+-- | A wrapped object that has an associated GLib type. This does not
+-- necessarily descend from `GObject`, that constraint is implemented
+-- by the `GObject` type below.
+class HasParentTypes a => TypedObject a where
+  -- | The `GType` for this object.
+  glibType :: IO GType
 
--- | Pointers to structs/unions without an associated `GType`.
-class ManagedPtrNewtype a => WrappedPtr a where
-    -- | Allocate a zero-initialized block of memory for the given type.
-    wrappedPtrCalloc :: IO (Ptr a)
-    -- | Make a copy of the given `WrappedPtr`.
-    wrappedPtrCopy   :: a -> IO a
-    -- | A pointer to a function for freeing the given pointer, or
-    -- `Nothing` is the memory associated to the pointer does not need
-    -- to be freed.
-    wrappedPtrFree   :: Maybe (GDestroyNotify a)
+-- | Chunks of memory whose allocation/deallocation info has been
+-- registered with the GLib type system.
+class (ManagedPtrNewtype a, TypedObject a) => GBoxed a
 
--- | A wrapped `GObject`.
-class (ManagedPtrNewtype a, HasParentTypes a) => GObject a where
-    -- | The `GType` for this object.
-    gobjectType :: IO GType
+-- | A wrapped `GObject`, or any other type that descends from it.
+class (ManagedPtrNewtype a, TypedObject a) => GObject a
+
+-- | Enums with an associated `GType`.
+class TypedObject a => BoxedEnum a
+
+-- | Flags with an associated `GType`.
+class TypedObject a => BoxedFlags a
 
 -- | A type identifier in the GLib type system. This is the low-level
 -- type associated with the representation in memory, when using this
diff --git a/Data/GI/Base/GClosure.hs b/Data/GI/Base/GClosure.hs
--- a/Data/GI/Base/GClosure.hs
+++ b/Data/GI/Base/GClosure.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE TypeFamilies, DataKinds #-}
 -- | Some helper functions for dealing with @GClosure@s.
 module Data.GI.Base.GClosure
     ( GClosure(..)
@@ -19,6 +20,7 @@
 import Data.GI.Base.CallStack (HasCallStack)
 import Data.GI.Base.ManagedPtr (newBoxed, newManagedPtr',
                                 disownManagedPtr, withManagedPtr)
+import Data.GI.Base.Overloading (ParentTypes, HasParentTypes)
 
 -- | The basic type. This corresponds to a wrapped @GClosure@ on the C
 -- side, which is a boxed object.
@@ -31,8 +33,17 @@
 foreign import ccall "g_closure_get_type" c_g_closure_get_type ::
     IO GType
 
-instance BoxedObject (GClosure a) where
-    boxedType _ = c_g_closure_get_type
+-- | There are no types in the bindings that a closure can be safely
+-- cast to.
+type instance ParentTypes (GClosure a) = '[]
+instance HasParentTypes (GClosure a)
+
+-- | Find the associated `GType` for the given closure.
+instance TypedObject (GClosure a) where
+  glibType = c_g_closure_get_type
+
+-- | `GClosure`s are registered as boxed in the GLib type system.
+instance GBoxed (GClosure a)
 
 foreign import ccall "g_cclosure_new" g_cclosure_new
     :: FunPtr a -> Ptr () -> FunPtr c -> IO (Ptr (GClosure a))
diff --git a/Data/GI/Base/GError.hsc b/Data/GI/Base/GError.hsc
--- a/Data/GI/Base/GError.hsc
+++ b/Data/GI/Base/GError.hsc
@@ -1,4 +1,5 @@
 {-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies, DataKinds #-}
 
 -- | To catch GError exceptions use the
 -- catchGError* or handleGError* functions. They work in a similar
@@ -70,9 +71,11 @@
 
 import System.IO.Unsafe (unsafePerformIO)
 
-import Data.GI.Base.BasicTypes (BoxedObject(..), GType(..), ManagedPtr)
+import Data.GI.Base.BasicTypes (GType(..), ManagedPtr, TypedObject(..),
+                                GBoxed)
 import Data.GI.Base.BasicConversions (withTextCString, cstringToText)
-import Data.GI.Base.ManagedPtr (wrapBoxed, withManagedPtr, copyBoxed)
+import Data.GI.Base.ManagedPtr (withManagedPtr, wrapBoxed, copyBoxed)
+import Data.GI.Base.Overloading (ParentTypes, HasParentTypes)
 import Data.GI.Base.Utils (allocMem, freeMem)
 
 #include <glib.h>
@@ -91,10 +94,18 @@
 
 instance Exception GError
 
+-- | There are no types in the bindings that a `GError` can be safely
+-- cast to.
+type instance ParentTypes GError = '[]
+instance HasParentTypes GError
+
 foreign import ccall "g_error_get_type" g_error_get_type :: IO GType
 
-instance BoxedObject GError where
-    boxedType _ = g_error_get_type
+instance TypedObject GError where
+  glibType = g_error_get_type
+
+-- | `GError`s are registered as boxed in the GLib type system.
+instance GBoxed GError
 
 -- | A GQuark.
 type GQuark = #type GQuark
diff --git a/Data/GI/Base/GObject.hsc b/Data/GI/Base/GObject.hsc
--- a/Data/GI/Base/GObject.hsc
+++ b/Data/GI/Base/GObject.hsc
@@ -59,8 +59,9 @@
 import Data.GI.Base.Attributes (AttrOp(..), AttrOpTag(..), AttrLabelProxy,
                                 attrConstruct, attrTransfer,
                                 AttrInfo(..))
-import Data.GI.Base.BasicTypes (CGType, GType(..), GObject(..),
+import Data.GI.Base.BasicTypes (CGType, GType(..), GObject,
                                 GDestroyNotify, ManagedPtr(..), GParamSpec(..),
+                                TypedObject(glibType),
                                 gtypeName)
 import Data.GI.Base.BasicConversions (withTextCString, cstringToText)
 import Data.GI.Base.CallStack (HasCallStack, prettyCallStack)
@@ -108,9 +109,9 @@
 -- | Construct the given `GObject`, given a set of actions
 -- constructing desired `GValue`s to set at construction time.
 new' :: (MonadIO m, GObject o) =>
-        (ManagedPtr o -> o) -> [IO (GValueConstruct o)] -> m o
+        (ManagedPtr o -> o) -> [m (GValueConstruct o)] -> m o
 new' constructor actions = do
-  props <- liftIO $ sequence (actions)
+  props <- sequence actions
   doConstructGObject constructor props
 
 -- | Construct the `GObject` given the list of `GValueConstruct`s.
@@ -121,7 +122,7 @@
   names <- mallocBytes (nprops * sizeOf nullPtr)
   values <- mallocBytes (nprops * gvalueSize)
   fill names values props
-  gtype <- gobjectType @o
+  gtype <- glibType @o
   result <- g_object_new gtype (fromIntegral nprops) names values
   freeStrings nprops names
   free values
@@ -243,7 +244,7 @@
     else do
       classInit <- mkClassInit (unwrapClassInit $ objectClassInit @o)
       instanceInit <- mkInstanceInit (unwrapInstanceInit $ objectInstanceInit @o)
-      (GType parentCGType) <- gobjectType @(GObjectParentType o)
+      (GType parentCGType) <- glibType @(GObjectParentType o)
       GType <$> register_gtype parentCGType cTypeName classInit instanceInit
 
    where
@@ -269,7 +270,7 @@
        case maybeGetSet of
          Nothing -> do
            pspecName <- g_param_spec_get_name pspecPtr >>= cstringToText
-           typeName <- gobjectType @o >>= gtypeName
+           typeName <- glibType @o >>= gtypeName
            dbgLog $ "WARNING: Attempting to set unknown property \""
                     <> pspecName <> "\" of type \"" <> T.pack typeName <> "\"."
          Just pgs -> (propSetter pgs) objPtr gvPtr
@@ -280,7 +281,7 @@
        case maybeGetSet of
          Nothing -> do
            pspecName <- g_param_spec_get_name pspecPtr >>= cstringToText
-           typeName <- gobjectType @o >>= gtypeName
+           typeName <- glibType @o >>= gtypeName
            dbgLog $ "WARNING: Attempting to get unknown property \""
                     <> pspecName <> "\" of type \"" <> T.pack typeName <> "\"."
          Just pgs -> (propGetter pgs) objPtr destGValuePtr
diff --git a/Data/GI/Base/GParamSpec.hsc b/Data/GI/Base/GParamSpec.hsc
--- a/Data/GI/Base/GParamSpec.hsc
+++ b/Data/GI/Base/GParamSpec.hsc
@@ -39,7 +39,7 @@
                                 disownManagedPtr,
                                 newObject, withTransient)
 import Data.GI.Base.BasicConversions (gflagsToWord, withTextCString)
-import Data.GI.Base.BasicTypes (GObject(..), GParamSpec(..),
+import Data.GI.Base.BasicTypes (GObject, GParamSpec(..),
                                 GType(..), IsGFlag, ManagedPtr)
 import Data.GI.Base.GQuark (GQuark(..), gQuarkFromString)
 import Data.GI.Base.GType (gtypeStablePtr)
diff --git a/Data/GI/Base/GValue.hsc b/Data/GI/Base/GValue.hsc
--- a/Data/GI/Base/GValue.hsc
+++ b/Data/GI/Base/GValue.hsc
@@ -1,5 +1,6 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DataKinds, TypeFamilies #-}
 module Data.GI.Base.GValue
     (
     -- * Constructing GValues
@@ -9,8 +10,17 @@
 
     , newGValue
     , buildGValue
+    , disownGValue
     , noGValue
+    , newGValueFromPtr
+    , wrapGValuePtr
+    , unsetGValue
 
+    -- * Packing GValues into arrays
+    , packGValueArray
+    , unpackGValueArrayWithLength
+    , mapGValueArrayWithLength
+
     -- * Setters and getters
     , set_string
     , get_string
@@ -65,13 +75,14 @@
 import Foreign.C.Types (CInt(..), CUInt(..), CFloat(..), CDouble(..),
                         CLong(..), CULong(..))
 import Foreign.C.String (CString)
-import Foreign.Ptr (Ptr, nullPtr)
+import Foreign.Ptr (Ptr, nullPtr, plusPtr)
 import Foreign.StablePtr (StablePtr, castStablePtrToPtr, castPtrToStablePtr)
 
 import Data.GI.Base.BasicTypes
 import Data.GI.Base.BasicConversions (cstringToText, textToCString)
 import Data.GI.Base.GType
 import Data.GI.Base.ManagedPtr
+import Data.GI.Base.Overloading (HasParentTypes, ParentTypes)
 import Data.GI.Base.Utils (callocBytes, freeMem)
 
 -- | Haskell-side representation of a @GValue@.
@@ -82,11 +93,20 @@
 noGValue = Nothing
 
 foreign import ccall unsafe "g_value_get_type" c_g_value_get_type ::
-    IO CGType
+    IO GType
 
-instance BoxedObject GValue where
-    boxedType _ = GType <$> c_g_value_get_type
+-- | There are no types in the bindings that a `GValue` can be safely
+-- cast to.
+type instance ParentTypes GValue = '[]
+instance HasParentTypes GValue
 
+-- | Find the associated `GType` for `GValue`.
+instance TypedObject GValue where
+  glibType = c_g_value_get_type
+
+-- | `GValue`s are registered as boxed in the GLib type system.
+instance GBoxed GValue
+
 foreign import ccall "g_value_init" g_value_init ::
     Ptr GValue -> CGType -> IO (Ptr GValue)
 
@@ -103,6 +123,15 @@
   gv <- wrapBoxed GValue gvptr
   return $! gv
 
+-- | Take ownership of a passed in 'Ptr'.
+wrapGValuePtr :: Ptr GValue -> IO GValue
+wrapGValuePtr ptr = wrapBoxed GValue ptr
+
+-- | Construct a Haskell wrapper for the given 'GValue', making a
+-- copy.
+newGValueFromPtr :: Ptr GValue -> IO GValue
+newGValueFromPtr ptr = newBoxed GValue ptr
+
 -- | A convenience function for building a new GValue and setting the
 -- initial value.
 buildGValue :: GType -> (GValue -> a -> IO ()) -> a -> IO GValue
@@ -111,6 +140,17 @@
   setter gv val
   return gv
 
+-- | Disown a `GValue`, i.e. do not unref the underlying object when
+-- the Haskell object is garbage collected.
+disownGValue :: GValue -> IO (Ptr GValue)
+disownGValue = disownManagedPtr
+
+foreign import ccall "g_value_unset" g_value_unset :: Ptr GValue -> IO ()
+
+-- | Unset the `GValue`, freeing all resources associated to it.
+unsetGValue :: Ptr GValue -> IO ()
+unsetGValue = g_value_unset
+
 -- | A convenience class for marshaling back and forth between Haskell
 -- values and `GValue`s.
 class IsGValue a where
@@ -404,3 +444,48 @@
 -- | Get the value of a `GValue` containing a `StablePtr`
 get_stablePtr :: GValue -> IO (StablePtr a)
 get_stablePtr gv = castPtrToStablePtr <$> withManagedPtr gv _get_boxed
+
+foreign import ccall g_value_copy :: Ptr GValue -> Ptr GValue -> IO ()
+foreign import ccall "_haskell_gi_g_value_get_type" g_value_get_type :: Ptr GValue -> IO CGType
+
+-- | Pack the given list of GValues contiguously into a C array
+packGValueArray :: [GValue] -> IO (Ptr GValue)
+packGValueArray gvalues = withManagedPtrList gvalues $ \ptrs -> do
+  let nitems = length ptrs
+  mem <- callocBytes $ #{size GValue} * nitems
+  fill mem ptrs
+  return mem
+  where fill :: Ptr GValue -> [Ptr GValue] -> IO ()
+        fill _ [] = return ()
+        fill ptr (x:xs) = do
+          gtype <- g_value_get_type x
+          _ <- g_value_init ptr gtype
+          g_value_copy x ptr
+          fill (ptr `plusPtr` #{size GValue}) xs
+
+-- | Unpack an array of contiguous GValues into a list of GValues.
+unpackGValueArrayWithLength :: Integral a =>
+                               a -> Ptr GValue -> IO [GValue]
+unpackGValueArrayWithLength nitems gvalues = go (fromIntegral nitems) gvalues
+  where go :: Int -> Ptr GValue -> IO [GValue]
+        go 0 _ = return []
+        go n ptr = do
+          gv <- callocBytes #{size GValue}
+          gtype <- g_value_get_type ptr
+          _ <- g_value_init gv gtype
+          g_value_copy ptr gv
+          wrapped <- wrapGValuePtr gv
+          (wrapped :) <$> go (n-1) (ptr `plusPtr` #{size GValue})
+
+-- | Map over the `GValue`s inside a C array.
+mapGValueArrayWithLength :: Integral a =>
+                            a -> (Ptr GValue -> IO c) -> Ptr GValue -> IO ()
+mapGValueArrayWithLength nvalues f arrayPtr
+  | (arrayPtr == nullPtr) = return ()
+  | (nvalues <= 0) = return ()
+  | otherwise = go (fromIntegral nvalues) arrayPtr
+  where go :: Int -> Ptr GValue -> IO ()
+        go 0 _ = return ()
+        go n ptr = do
+          _ <- f ptr
+          go (n-1) (ptr `plusPtr` #{size GValue})
diff --git a/Data/GI/Base/ManagedPtr.hs b/Data/GI/Base/ManagedPtr.hs
--- a/Data/GI/Base/ManagedPtr.hs
+++ b/Data/GI/Base/ManagedPtr.hs
@@ -51,6 +51,7 @@
 import Control.Applicative ((<$>))
 #endif
 import Control.Monad (when, void)
+import Control.Monad.Fix (mfix)
 
 import Data.Coerce (coerce)
 import Data.IORef (newIORef, readIORef, writeIORef, IORef)
@@ -129,12 +130,12 @@
 
 -- | Do not run the finalizers upon garbage collection of the
 -- `ManagedPtr`.
-disownManagedPtr :: forall a. (HasCallStack, ManagedPtrNewtype a) => a -> IO (Ptr a)
+disownManagedPtr :: forall a b. (HasCallStack, ManagedPtrNewtype a) => a -> IO (Ptr b)
 disownManagedPtr managed = do
   ptr <- unsafeManagedPtrGetPtr managed
   writeIORef (managedPtrIsDisowned c) (Just callStack)
-  return ptr
-    where c = coerce managed :: ManagedPtr ()
+  return (castPtr ptr)
+    where c = toManagedPtr managed
 
 -- | Perform an IO action on the 'Ptr' inside a managed pointer.
 withManagedPtr :: (HasCallStack, ManagedPtrNewtype a) => a -> (Ptr a -> IO c) -> IO c
@@ -184,7 +185,7 @@
 unsafeManagedPtrCastPtr :: forall a b. (HasCallStack, ManagedPtrNewtype a) =>
                            a -> IO (Ptr b)
 unsafeManagedPtrCastPtr m = do
-    let c = coerce m :: ManagedPtr ()
+    let c = toManagedPtr m
         ptr = (castPtr . unsafeForeignPtrToPtr . managedForeignPtr) c
     disowned <- readIORef (managedPtrIsDisowned c)
     maybe (return ptr) (notOwnedWarning ptr) disowned
@@ -204,7 +205,7 @@
 -- (i.e. it has not been garbage collected by the runtime) at the
 -- point that this is called.
 touchManagedPtr :: forall a. ManagedPtrNewtype a => a -> IO ()
-touchManagedPtr m = let c = coerce m :: ManagedPtr ()
+touchManagedPtr m = let c = toManagedPtr m
                     in (touchForeignPtr . managedForeignPtr) c
 
 -- Safe casting machinery
@@ -212,39 +213,45 @@
     c_check_object_type :: Ptr o -> CGType -> IO CInt
 
 -- | Check whether the given object is an instance of the given type.
-checkInstanceType :: GObject o => o -> GType -> IO Bool
+checkInstanceType :: (ManagedPtrNewtype o, TypedObject o) =>
+                     o -> GType -> IO Bool
 checkInstanceType obj (GType cgtype) = withManagedPtr obj $ \objPtr -> do
   check <- c_check_object_type objPtr cgtype
   return $ check /= 0
 
--- | Cast to the given type, checking that the cast is valid. If it is
--- not, we return `Nothing`. Usage:
+-- | Cast from one object type to another, checking that the cast is
+-- valid. If it is not, we return `Nothing`. Usage:
 --
 -- > maybeWidget <- castTo Widget label
-castTo :: forall o o'. (GObject o, GObject o') =>
+castTo :: forall o o'. (HasCallStack,
+                        ManagedPtrNewtype o, TypedObject o,
+                        ManagedPtrNewtype o', TypedObject o',
+                        GObject o') =>
           (ManagedPtr o' -> o') -> o -> IO (Maybe o')
-castTo constructor obj = withManagedPtr obj $ \objPtr -> do
-  gtype <- gobjectType @o'
+castTo constructor obj = do
+  gtype <- glibType @o'
   isInstance <- checkInstanceType obj gtype
   if isInstance
-    then Just <$> newObject constructor objPtr
+    then return . Just . constructor . coerce $ toManagedPtr obj
     else return Nothing
 
--- | Cast to the given type, assuming that the cast will succeed. This
--- function will call `error` if the cast is illegal.
-unsafeCastTo :: forall o o'. (HasCallStack, GObject o, GObject o') =>
+-- | Cast a typed object to a new type (without any assumption that
+-- both types descend from `GObject`), assuming that the cast will
+-- succeed. This function will call `error` if the cast is illegal.
+unsafeCastTo :: forall o o'. (HasCallStack,
+                              ManagedPtrNewtype o, TypedObject o,
+                              ManagedPtrNewtype o', TypedObject o') =>
                 (ManagedPtr o' -> o') -> o -> IO o'
-unsafeCastTo constructor obj =
-  withManagedPtr obj $ \objPtr -> do
-    gtype <- gobjectType @o'
+unsafeCastTo constructor obj = do
+    gtype <- glibType @o'
     isInstance <- checkInstanceType obj gtype
     if not isInstance
       then do
-      srcType <- gobjectType @o >>= gtypeName
-      destType <- gobjectType @o' >>= gtypeName
+      srcType <- glibType @o >>= gtypeName
+      destType <- glibType @o' >>= gtypeName
       error $ "unsafeCastTo :: invalid conversion from " ++ srcType ++ " to "
         ++ destType ++ " requested."
-      else newObject constructor objPtr
+      else return (constructor $ coerce $ toManagedPtr obj)
 
 -- Reference counting for constructors
 foreign import ccall "&dbg_g_object_unref"
@@ -335,32 +342,32 @@
 
 -- | Construct a Haskell wrapper for the given boxed object. We make a
 -- copy of the object.
-newBoxed :: forall a. (HasCallStack, BoxedObject a) => (ManagedPtr a -> a) -> Ptr a -> IO a
+newBoxed :: forall a. (HasCallStack, GBoxed a) => (ManagedPtr a -> a) -> Ptr a -> IO a
 newBoxed constructor ptr = do
-  GType gtype <- boxedType (undefined :: a)
+  GType gtype <- glibType @a
   ptr' <- g_boxed_copy gtype ptr
   fPtr <- newManagedPtr ptr' (boxed_free_helper gtype ptr')
   return $! constructor fPtr
 
 -- | Like 'newBoxed', but we do not make a copy (we "steal" the passed
 -- object, so now it is managed by the Haskell runtime).
-wrapBoxed :: forall a. (HasCallStack, BoxedObject a) => (ManagedPtr a -> a) -> Ptr a -> IO a
+wrapBoxed :: forall a. (HasCallStack, GBoxed a) => (ManagedPtr a -> a) -> Ptr a -> IO a
 wrapBoxed constructor ptr = do
-  GType gtype <- boxedType (undefined :: a)
+  GType gtype <- glibType @a
   fPtr <- newManagedPtr ptr (boxed_free_helper gtype ptr)
   return $! constructor fPtr
 
 -- | Make a copy of the given boxed object.
-copyBoxed :: forall a. (HasCallStack, BoxedObject a) => a -> IO (Ptr a)
+copyBoxed :: forall a. (HasCallStack, GBoxed a) => a -> IO (Ptr a)
 copyBoxed b = do
-  GType gtype <- boxedType b
+  GType gtype <- glibType @a
   withManagedPtr b (g_boxed_copy gtype)
 
 -- | Like 'copyBoxed', but acting directly on a pointer, instead of a
 -- managed pointer.
-copyBoxedPtr :: forall a. BoxedObject a => Ptr a -> IO (Ptr a)
+copyBoxedPtr :: forall a. GBoxed a => Ptr a -> IO (Ptr a)
 copyBoxedPtr ptr = do
-  GType gtype <- boxedType (undefined :: a)
+  GType gtype <- glibType @a
   g_boxed_copy gtype ptr
 
 foreign import ccall "g_boxed_free" g_boxed_free ::
@@ -368,53 +375,51 @@
 
 -- | Free the memory associated with a boxed object. Note that this
 -- disowns the associated `ManagedPtr` via `disownManagedPtr`.
-freeBoxed :: forall a. (HasCallStack, BoxedObject a) => a -> IO ()
+freeBoxed :: forall a. (HasCallStack, GBoxed a) => a -> IO ()
 freeBoxed boxed = do
-  GType gtype <- boxedType (undefined :: a)
+  GType gtype <- glibType @a
   ptr <- disownManagedPtr boxed
   dbgDealloc boxed
   g_boxed_free gtype ptr
 
 -- | Disown a boxed object, that is, do not free the associated
 -- foreign GBoxed when the Haskell object gets garbage
--- collected. Returns the pointer to the underlying `BoxedObject`.
-disownBoxed :: (HasCallStack, BoxedObject a) => a -> IO (Ptr a)
+-- collected. Returns the pointer to the underlying `GBoxed`.
+disownBoxed :: (HasCallStack, GBoxed a) => a -> IO (Ptr a)
 disownBoxed = disownManagedPtr
 
 -- | Wrap a pointer, taking ownership of it.
-wrapPtr :: (HasCallStack, WrappedPtr a) => (ManagedPtr a -> a) -> Ptr a -> IO a
-wrapPtr constructor ptr = do
-  fPtr <- case wrappedPtrFree of
-            Nothing -> newManagedPtr_ ptr
-            Just finalizer -> newManagedPtr' finalizer ptr
+wrapPtr :: (HasCallStack, BoxedPtr a) => (ManagedPtr a -> a) -> Ptr a -> IO a
+wrapPtr constructor ptr = mfix $ \wrapped -> do
+  fPtr <- newManagedPtr ptr (boxedPtrFree wrapped)
   return $! constructor fPtr
 
 -- | Wrap a pointer, making a copy of the data.
-newPtr :: (HasCallStack, WrappedPtr a) => (ManagedPtr a -> a) -> Ptr a -> IO a
+newPtr :: (HasCallStack, BoxedPtr a) => (ManagedPtr a -> a) -> Ptr a -> IO a
 newPtr constructor ptr = do
   tmpWrap <- newManagedPtr_ ptr
-  ptr' <- wrappedPtrCopy (constructor tmpWrap)
+  ptr' <- boxedPtrCopy (constructor tmpWrap)
   return $! ptr'
 
 -- | Make a copy of a wrapped pointer using @memcpy@ into a freshly
 -- allocated memory region of the given size.
-copyBytes :: WrappedPtr a => Int -> Ptr a -> IO (Ptr a)
+copyBytes :: (HasCallStack, CallocPtr a) => Int -> Ptr a -> IO (Ptr a)
 copyBytes size ptr = do
-  ptr' <- wrappedPtrCalloc
+  ptr' <- boxedPtrCalloc
   memcpy ptr' ptr size
   return ptr'
 
 foreign import ccall unsafe "g_thread_self" g_thread_self :: IO (Ptr ())
 
--- | Print a debug message for deallocs if the @HASKELL_GI_DEBUG_MEM@
--- environment variable has been set.
+-- | Same as `dbgDeallocPtr`, but for `ManagedPtr`s, and no callstack
+-- needs to be provided.
 dbgDealloc :: (HasCallStack, ManagedPtrNewtype a) => a -> IO ()
 dbgDealloc m = do
   env <- lookupEnv "HASKELL_GI_DEBUG_MEM"
   case env of
     Nothing -> return ()
     Just _ -> do
-      let mPtr = coerce m :: ManagedPtr ()
+      let mPtr = toManagedPtr m
           ptr = (unsafeForeignPtrToPtr . managedForeignPtr) mPtr
       threadPtr <- g_thread_self
       hPutStrLn stderr ("Releasing <" ++ show ptr ++ "> from thread ["
diff --git a/Data/GI/Base/Properties.hsc b/Data/GI/Base/Properties.hsc
--- a/Data/GI/Base/Properties.hsc
+++ b/Data/GI/Base/Properties.hsc
@@ -27,6 +27,7 @@
     , setObjectPropertyHash
     , setObjectPropertyCallback
     , setObjectPropertyGError
+    , setObjectPropertyGValue
 
     , getObjectPropertyString
     , getObjectPropertyStringArray
@@ -54,6 +55,7 @@
     , getObjectPropertyHash
     , getObjectPropertyCallback
     , getObjectPropertyGError
+    , getObjectPropertyGValue
 
     , constructObjectPropertyString
     , constructObjectPropertyStringArray
@@ -81,6 +83,7 @@
     , constructObjectPropertyHash
     , constructObjectPropertyCallback
     , constructObjectPropertyGError
+    , constructObjectPropertyGValue
     ) where
 
 #if !MIN_VERSION_base(4,8,0)
@@ -90,7 +93,6 @@
 
 import qualified Data.ByteString.Char8 as B
 import Data.Text (Text)
-import Data.Proxy (Proxy(..))
 
 import Data.GI.Base.BasicTypes
 import Data.GI.Base.BasicConversions
@@ -341,44 +343,44 @@
 setObjectPropertyObject :: forall a b. (GObject a, GObject b) =>
                            a -> String -> Maybe b -> IO ()
 setObjectPropertyObject obj propName maybeObject = do
-  gtype <- gobjectType @b
+  gtype <- glibType @b
   maybeWithManagedPtr maybeObject $ \objectPtr ->
       setObjectProperty obj propName objectPtr set_object gtype
 
 constructObjectPropertyObject :: forall a o. GObject a =>
                                  String -> Maybe a -> IO (GValueConstruct o)
 constructObjectPropertyObject propName maybeObject = do
-  gtype <- gobjectType @a
+  gtype <- glibType @a
   maybeWithManagedPtr maybeObject $ \objectPtr ->
       constructObjectProperty propName objectPtr set_object gtype
 
 getObjectPropertyObject :: forall a b. (GObject a, GObject b) =>
                            a -> String -> (ManagedPtr b -> b) -> IO (Maybe b)
 getObjectPropertyObject obj propName constructor = do
-  gtype <- gobjectType @b
+  gtype <- glibType @b
   getObjectProperty obj propName
                         (\val -> (get_object val :: IO (Ptr b))
                             >>= flip convertIfNonNull (newObject constructor))
                       gtype
 
-setObjectPropertyBoxed :: forall a b. (GObject a, BoxedObject b) =>
+setObjectPropertyBoxed :: forall a b. (GObject a, GBoxed b) =>
                           a -> String -> Maybe b -> IO ()
 setObjectPropertyBoxed obj propName maybeBoxed = do
-  gtype <- boxedType (undefined :: b)
+  gtype <- glibType @b
   maybeWithManagedPtr maybeBoxed $ \boxedPtr ->
         setObjectProperty obj propName boxedPtr set_boxed gtype
 
-constructObjectPropertyBoxed :: forall a o. (BoxedObject a) =>
+constructObjectPropertyBoxed :: forall a o. (GBoxed a) =>
                                 String -> Maybe a -> IO (GValueConstruct o)
 constructObjectPropertyBoxed propName maybeBoxed = do
-  gtype <- boxedType (undefined :: a)
+  gtype <- glibType @a
   maybeWithManagedPtr maybeBoxed $ \boxedPtr ->
       constructObjectProperty propName boxedPtr set_boxed gtype
 
-getObjectPropertyBoxed :: forall a b. (GObject a, BoxedObject b) =>
+getObjectPropertyBoxed :: forall a b. (GObject a, GBoxed b) =>
                           a -> String -> (ManagedPtr b -> b) -> IO (Maybe b)
 getObjectPropertyBoxed obj propName constructor = do
-  gtype <- boxedType (undefined :: b)
+  gtype <- glibType @b
   getObjectProperty obj propName (get_boxed >=>
                                   flip convertIfNonNull (newBoxed constructor))
                     gtype
@@ -411,17 +413,17 @@
                        flip convertIfNonNull unpackZeroTerminatedUTF8CArray)
                       gtypeStrv
 
-setObjectPropertyEnum :: (GObject a, Enum b, BoxedEnum b) =>
+setObjectPropertyEnum :: forall a b. (GObject a, Enum b, BoxedEnum b) =>
                          a -> String -> b -> IO ()
 setObjectPropertyEnum obj propName enum = do
-  gtype <- boxedEnumType enum
+  gtype <- glibType @b
   let cEnum = (fromIntegral . fromEnum) enum
   setObjectProperty obj propName cEnum set_enum gtype
 
-constructObjectPropertyEnum :: (Enum a, BoxedEnum a) =>
+constructObjectPropertyEnum :: forall a o. (Enum a, BoxedEnum a) =>
                                String -> a -> IO (GValueConstruct o)
 constructObjectPropertyEnum propName enum = do
-  gtype <- boxedEnumType enum
+  gtype <- glibType @a
   let cEnum = (fromIntegral . fromEnum) enum
   constructObjectProperty propName cEnum set_enum gtype
 
@@ -429,7 +431,7 @@
                                       Enum b, BoxedEnum b) =>
                          a -> String -> IO b
 getObjectPropertyEnum obj propName = do
-  gtype <- boxedEnumType (undefined :: b)
+  gtype <- glibType @b
   getObjectProperty obj propName
                     (\val -> toEnum . fromIntegral <$> get_enum val)
                     gtype
@@ -438,20 +440,20 @@
                           a -> String -> [b] -> IO ()
 setObjectPropertyFlags obj propName flags = do
   let cFlags = gflagsToWord flags
-  gtype <- boxedFlagsType (Proxy :: Proxy b)
+  gtype <- glibType @b
   setObjectProperty obj propName cFlags set_flags gtype
 
 constructObjectPropertyFlags :: forall a o. (IsGFlag a, BoxedFlags a)
                                 => String -> [a] -> IO (GValueConstruct o)
 constructObjectPropertyFlags propName flags = do
   let cFlags = gflagsToWord flags
-  gtype <- boxedFlagsType (Proxy :: Proxy a)
+  gtype <- glibType @a
   constructObjectProperty propName cFlags set_flags gtype
 
 getObjectPropertyFlags :: forall a b. (GObject a, IsGFlag b, BoxedFlags b) =>
                           a -> String -> IO [b]
 getObjectPropertyFlags obj propName = do
-  gtype <- boxedFlagsType (Proxy :: Proxy b)
+  gtype <- glibType @b
   getObjectProperty obj propName
                         (\val -> wordToGFlags <$> get_flags val)
                         gtype
@@ -575,3 +577,18 @@
                             a -> String -> IO (Maybe GError)
 getObjectPropertyGError obj propName =
   getObjectPropertyBoxed obj propName GError
+
+-- | Set a property of type `GValue`.
+setObjectPropertyGValue :: forall a. GObject a =>
+                           a -> String -> Maybe GValue -> IO ()
+setObjectPropertyGValue = setObjectPropertyBoxed
+
+-- | Construct a property of type `GValue`.
+constructObjectPropertyGValue :: String -> Maybe GValue -> IO (GValueConstruct o)
+constructObjectPropertyGValue = constructObjectPropertyBoxed
+
+-- | Get the value of a property of type `GValue`.
+getObjectPropertyGValue :: forall a. GObject a =>
+                           a -> String -> IO (Maybe GValue)
+getObjectPropertyGValue obj propName =
+  getObjectPropertyBoxed obj propName GValue
diff --git a/Data/GI/Base/Utils.hsc b/Data/GI/Base/Utils.hsc
--- a/Data/GI/Base/Utils.hsc
+++ b/Data/GI/Base/Utils.hsc
@@ -1,5 +1,5 @@
 {-# LANGUAGE ScopedTypeVariables, TupleSections, OverloadedStrings,
-    FlexibleContexts, ConstraintKinds #-}
+    FlexibleContexts, ConstraintKinds, TypeApplications #-}
 {- | Assorted utility functions for bindings. -}
 module Data.GI.Base.Utils
     ( whenJust
@@ -46,7 +46,8 @@
 import Foreign.Ptr (Ptr, nullPtr, FunPtr, nullFunPtr, freeHaskellFunPtr)
 import Foreign.Storable (Storable(..))
 
-import Data.GI.Base.BasicTypes (GType(..), CGType, BoxedObject(..),
+import Data.GI.Base.BasicTypes (GType(..), CGType, GBoxed,
+                                TypedObject(glibType),
                                 UnexpectedNullPointerReturn(..))
 import Data.GI.Base.CallStack (HasCallStack, callStack, prettyCallStack)
 
@@ -127,10 +128,10 @@
 -- in particular may well be different from a plain g_malloc. In
 -- particular g_slice_alloc is often used for allocating boxed
 -- objects, which are then freed using g_slice_free.
-callocBoxedBytes :: forall a. BoxedObject a => Int -> IO (Ptr a)
+callocBoxedBytes :: forall a. GBoxed a => Int -> IO (Ptr a)
 callocBoxedBytes n = do
   ptr <- callocBytes n
-  GType cgtype <- boxedType (undefined :: a)
+  GType cgtype <- glibType @a
   result <- g_boxed_copy cgtype ptr
   freeMem ptr
   return result
diff --git a/c/hsgclosure.c b/c/hsgclosure.c
--- a/c/hsgclosure.c
+++ b/c/hsgclosure.c
@@ -86,7 +86,7 @@
   va_end(args);
 }
 
-int check_object_type(void *instance, GType type)
+int check_object_type (void *instance, GType type)
 {
   int result;
 
@@ -98,6 +98,11 @@
   }
 
   return result;
+}
+
+GType _haskell_gi_g_value_get_type (GValue *gvalue)
+{
+  return G_VALUE_TYPE (gvalue);
 }
 
 /* Information about a boxed type to free */
diff --git a/haskell-gi-base.cabal b/haskell-gi-base.cabal
--- a/haskell-gi-base.cabal
+++ b/haskell-gi-base.cabal
@@ -1,8 +1,8 @@
 name:                haskell-gi-base
-version:             0.23.0
+version:             0.24.0
 synopsis:            Foundation for libraries generated by haskell-gi
 description:         Foundation for libraries generated by haskell-gi
-homepage:            https://github.com/haskell-gi/haskell-gi-base
+homepage:            https://github.com/haskell-gi/haskell-gi
 license:             LGPL-2.1
                      -- or above
 license-file:        LICENSE
@@ -19,7 +19,7 @@
 
 source-repository head
   type: git
-  location: git://github.com/haskell-gi/haskell-gi-base.git
+  location: git://github.com/haskell-gi/haskell-gi.git
 
 library
   exposed-modules:     Data.GI.Base,
@@ -52,7 +52,7 @@
 
   ghc-options: -Wall -Wno-redundant-constraints -fwarn-incomplete-patterns
 
-  build-tools:         hsc2hs
+  build-tool-depends:  hsc2hs:hsc2hs >= 0.68.5
   cc-options:          -fPIC
   default-language:    Haskell2010
   default-extensions:  CPP, ForeignFunctionInterface, DoAndIfThenElse, MonoLocalBinds
