diff --git a/kgb/spies.py b/kgb/spies.py
index 5ed4595741beb9a5819d560899168424c17fd781..e540f0b744526344ded0fc93c62c750cdd34638e 100644
--- a/kgb/spies.py
+++ b/kgb/spies.py
@@ -328,8 +328,8 @@ class FunctionSpy(object):
             if pyver[0] >= 3:
                 method_type_args.append(self.owner)
 
-            setattr(self.owner, self.func_name,
-                    types.MethodType(real_func, self.owner))
+            self._set_method(self.owner, self.func_name,
+                             types.MethodType(real_func, self.owner))
 
         self._real_func = real_func
 
@@ -552,7 +552,7 @@ class FunctionSpy(object):
         setattr(self._real_func, FUNC_CODE_ATTR, self._old_code)
 
         if self.owner is not None:
-            setattr(self.owner, self.func_name, self.orig_func)
+            self._set_method(self.owner, self.func_name, self.orig_func)
 
         if unregister:
             self.agency.spies.remove(self)
@@ -852,6 +852,30 @@ class FunctionSpy(object):
 
         return cloned_func
 
+    def _set_method(self, owner, name, method):
+        """Set a new method on an object.
+
+        This will set the method using a standard :py:func:`setattr` if
+        working on a class, or using :py:meth:`object.__setattr__` if working
+        on an instance (in order to avoid triggering a subclass-defined version
+        of :py:meth:`~object.__setattr__`, which might lose or override our
+        spy).
+
+        Args:
+            owner (type or object):
+                The class or instance to set the method on.
+
+            name (unicode):
+                The name of the attribute to set for the method.
+
+            method (types.MethodType):
+                The method to set.
+        """
+        if inspect.isclass(owner):
+            setattr(owner, name, method)
+        else:
+            object.__setattr__(owner, name, method)
+
     def _format_call_args(self, argspec):
         """Format arguments to pass in for forwarding a call.
 
diff --git a/kgb/tests/test_function_spy.py b/kgb/tests/test_function_spy.py
index cddd78a1cef7c13927dc69187ddb6d374612c8e1..ef0a93cdb2980cc2c28ee9fc8ae9ee88ced80edd 100644
--- a/kgb/tests/test_function_spy.py
+++ b/kgb/tests/test_function_spy.py
@@ -265,6 +265,32 @@ class FunctionSpyTests(TestCase):
 
         self.assertIn(', in setup_spy', text_type(cm.exception))
 
+    def test_construction_with_bound_method_and_custom_setattr(self):
+        """Testing FunctionSpy constructions with a bound method on a class
+        containing a custom __setattr__
+        """
+        class MyObject(object):
+            def __setattr__(self, key, value):
+                assert False
+
+            def foo(self):
+                pass
+
+        obj = MyObject()
+        orig_foo = obj.foo
+
+        spy = self.agency.spy_on(obj.foo)
+        self.assertEqual(spy.orig_func, orig_foo)
+        self.assertNotEqual(MyObject.foo, spy)
+        self.assertEqual(spy.func_name, 'foo')
+        self.assertEqual(spy.func_type, spy.TYPE_BOUND_METHOD)
+        self.assertIsInstance(obj.foo, types.MethodType)
+        self.assertTrue(hasattr(obj.foo, 'spy'))
+        self.assertTrue(hasattr(obj.foo, 'called_with'))
+
+        obj2 = MyObject()
+        self.assertFalse(hasattr(obj2.foo, 'spy'))
+
     def test_construction_with_non_function(self):
         """Testing FunctionSpy constructions with non-function"""
         with self.assertRaises(ValueError) as cm:
@@ -883,6 +909,26 @@ class FunctionSpyTests(TestCase):
         spy.unspy()
         self.assertEqual(obj.do_math.__dict__, func_dict)
 
+    def test_unspy_with_bound_method_and_custom_setattr(self):
+        """Testing FunctionSpy.unspy with a boudn method on a class containing
+        a custom __setattr__
+        """
+        class MyObject(object):
+            def __setattr__(self, key, value):
+                assert False
+
+            def foo(self):
+                pass
+
+        obj = MyObject()
+        func_dict = obj.foo.__dict__.copy()
+
+        spy = self.agency.spy_on(obj.foo)
+        self.assertNotEqual(obj.foo.__dict__, func_dict)
+
+        spy.unspy()
+        self.assertEqual(obj.foo.__dict__, func_dict)
+
     def test_unspy_and_unbound_method(self):
         """Testing FunctionSpy.unspy and unbound method"""
         func_dict = MathClass.do_math.__dict__.copy()
