diff --git a/gen_wrap.py b/gen_wrap.py
index 6d4fdd60139c9b324266141fa2083b63604edb2f..8cca026a5b96b29c74f19a226384b6973500da50 100644
--- a/gen_wrap.py
+++ b/gen_wrap.py
@@ -278,10 +278,12 @@ libc_ffi.cdef('''
 libc = libc_ffi.dlopen(None)
 
 
-class Error(RuntimeError):
+class Error(StandardError):
     pass
 
 
+class IslTypeError(Error, TypeError):
+    pass
 
 _context_use_map = {}
 
@@ -1006,7 +1008,7 @@ def write_method_wrapper(gen, cls_name, meth):
                     .format(
                         name=arg.name, py_cls=arg_py_cls))
             with Indentation(pre_call):
-                pre_call('raise Error("{name} is not a {py_cls}")'
+                pre_call('raise IslTypeError("{name} is not a {py_cls}")'
                     .format(
                         name=arg.name, py_cls=arg_py_cls))
 
diff --git a/islpy/__init__.py b/islpy/__init__.py
index fa907d781aab3883d62c857538b08efa6d1ecb48..098e71e65d3c306dcf6c1d5766f5314bfa3f7bb1 100644
--- a/islpy/__init__.py
+++ b/islpy/__init__.py
@@ -135,7 +135,7 @@ def _add_functionality():
 
     # {{{ generic initialization, pickling
 
-    def obj_new_from_string(cls, s, context=None):
+    def obj_init(self, s, context=None):
         """Construct a new object from :class:`str` s.
 
         :arg context: a :class:`islpy.Context` to use. If not supplied, use a
@@ -145,13 +145,8 @@ def _add_functionality():
         if context is None:
             context = _DEFAULT_CONTEXT
 
-        result = cls.read_from_str(context, s)
-        result._made_from_string = True
-        return result
-
-    def obj_bogus_init(self, s, context=None):
-        assert self._made_from_string
-        del self._made_from_string
+        new_me = self.read_from_str(context, s)
+        self._setup(new_me._release())
 
     def generic_getstate(self):
         ctx = self.get_ctx()
@@ -166,8 +161,7 @@ def _add_functionality():
 
     for cls in ALL_CLASSES:
         if hasattr(cls, "read_from_str"):
-            cls.__new__ = staticmethod(obj_new_from_string)
-            cls.__init__ = obj_bogus_init
+            cls.__init__ = obj_init
             cls.__getstate__ = generic_getstate
             cls.__setstate__ = generic_setstate
 
@@ -790,44 +784,60 @@ def _add_functionality():
     # note: automatic upcasts for method arguments are provided through
     # 'implicitly_convertible' on the C++ side of the wrapper.
 
-    class UpcastWrapper(object):
-        def __init__(self, method, upcast):
-            self.method = method
-            self.upcast = upcast
+    def make_new_upcast_wrapper(method, upcast):
+        # This function provides a scope in which method and upcast
+        # are not changed from one iteration of the enclosing for
+        # loop to the next.
+
+        def wrapper(basic_instance, *args, **kwargs):
+            special_instance = upcast(basic_instance)
+            return method(special_instance, *args, **kwargs)
+
+        return wrapper
+
+    def make_existing_upcast_wrapper(basic_method, special_method, upcast):
+        # This function provides a scope in which method and upcast
+        # are not changed from one iteration of the enclosing for
+        # loop to the next.
+
+        def wrapper(basic_instance, *args, **kwargs):
+            try:
+                return basic_method(basic_instance, *args, **kwargs)
+            except _isl.IslTypeError:
+                special_instance = upcast(basic_instance)
+                return special_method(special_instance, *args, **kwargs)
+
+        return wrapper
 
     def add_upcasts(basic_class, special_class, upcast_method):
         from functools import update_wrapper
         from inspect import ismethod
 
         for method_name in dir(special_class):
-            # do not overwrite existing methods
-            if hasattr(basic_class, method_name):
-                continue
+            special_method = getattr(special_class, method_name)
 
-            method = getattr(special_class, method_name)
-
-            my_ismethod = ismethod(method)
-            for meth_superclass in type(method).__mro__:
-                if "function" in meth_superclass.__name__:
-                    # inspect.ismethod does not work on Boost.Py callables in Py3,
-                    # hence this hack.
-                    my_ismethod = True
-                    break
+            if not ismethod(special_method):
+                continue
 
-            if my_ismethod:
-                def make_wrapper(method, upcast):
-                    # This function provides a scope in which method and upcast
-                    # are not changed from one iteration of the enclosing for
-                    # loop to the next.
+            if hasattr(basic_class, method_name):
+                # method already exists in basic class
+                basic_method = getattr(basic_class, method_name)
 
-                    def wrapper(basic_instance, *args, **kwargs):
-                        special_instance = upcast(basic_instance)
-                        return method(special_instance, *args, **kwargs)
+                if not ismethod(basic_method):
+                    continue
 
-                    return wrapper
+                wrapper = make_existing_upcast_wrapper(
+                        basic_method, special_method, upcast_method)
+                setattr(
+                        basic_class, method_name,
+                        update_wrapper(wrapper, basic_method))
+            else:
+                # method does not yet exists in basic class
 
-                wrapper = make_wrapper(method, upcast_method)
-                setattr(basic_class, method_name, update_wrapper(wrapper, method))
+                wrapper = make_new_upcast_wrapper(special_method, upcast_method)
+                setattr(
+                        basic_class, method_name,
+                        update_wrapper(wrapper, special_method))
 
     for args_triple in [
             (BasicSet, Set, Set.from_basic_set),