diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp
index c3a224103d..b542299d00 100644
--- a/libraries/metavoxels/src/SharedObject.cpp
+++ b/libraries/metavoxels/src/SharedObject.cpp
@@ -63,6 +63,12 @@ SharedObject* SharedObject::clone() const {
 
 bool SharedObject::equals(const SharedObject* other) const {
     // default behavior is to compare the properties
+    if (!other) {
+        return false;
+    }
+    if (other == this) {
+        return true;
+    }
     const QMetaObject* metaObject = this->metaObject();
     if (metaObject != other->metaObject()) {
         return false;
diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h
index 44bfb73a22..f83079b0fa 100644
--- a/libraries/metavoxels/src/SharedObject.h
+++ b/libraries/metavoxels/src/SharedObject.h
@@ -173,6 +173,11 @@ template<class T, SharedObjectFn Inc, SharedObjectFn Dec> uint qHash(
     return qHash(pointer.data(), seed);
 }
 
+template<class T, SharedObjectFn Inc, SharedObjectFn Dec, class X, SharedObjectFn Inc2, SharedObjectFn Dec2> bool equals(
+        const SharedObjectPointerTemplate<T, Inc, Dec>& first, const SharedObjectPointerTemplate<X, Inc2, Dec2>& second) {
+    return first ? first->equals(second) : !second;
+}
+
 typedef SharedObjectPointerTemplate<SharedObject> SharedObjectPointer;
 
 Q_DECLARE_METATYPE(SharedObjectPointer)
diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp
index 530f7e3108..f06658da68 100644
--- a/tests/metavoxels/src/MetavoxelTests.cpp
+++ b/tests/metavoxels/src/MetavoxelTests.cpp
@@ -12,6 +12,9 @@
 
 #include "MetavoxelTests.h"
 
+REGISTER_META_OBJECT(TestSharedObjectA)
+REGISTER_META_OBJECT(TestSharedObjectB)
+
 MetavoxelTests::MetavoxelTests(int& argc, char** argv) :
     QCoreApplication(argc, argv) {
 }
@@ -26,6 +29,8 @@ static int reliableMessagesSent = 0;
 static int reliableMessagesReceived = 0;
 static int streamedBytesSent = 0;
 static int streamedBytesReceived = 0;
+static int sharedObjectsCreated = 0;
+static int sharedObjectsDestroyed = 0;
 
 bool MetavoxelTests::run() {
     
@@ -54,6 +59,7 @@ bool MetavoxelTests::run() {
     qDebug() << "Sent" << reliableMessagesSent << "reliable messages, received" << reliableMessagesReceived;
     qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived;
     qDebug() << "Sent" << datagramsSent << "datagrams, received" << datagramsReceived;
+    qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed;
     
     qDebug() << "All tests passed!";
     
@@ -74,6 +80,15 @@ static QByteArray createRandomBytes() {
     return createRandomBytes(MIN_BYTES, MAX_BYTES);
 }
 
+static SharedObjectPointer createRandomSharedObject() {
+    switch (randIntInRange(0, 2)) {
+        case 0: return new TestSharedObjectA(randFloat());
+        case 1: return new TestSharedObjectB();
+        case 2:
+        default: return SharedObjectPointer();
+    }
+}
+
 Endpoint::Endpoint(const QByteArray& datagramHeader) :
     _sequencer(new DatagramSequencer(datagramHeader, this)),
     _highPriorityMessagesToSend(0.0f),
@@ -110,7 +125,7 @@ static QVariant createRandomMessage() {
             return QVariant::fromValue(message);
         }
         case 1: {
-            TestMessageB message = { createRandomBytes() };
+            TestMessageB message = { createRandomBytes(), createRandomSharedObject() };
             return QVariant::fromValue(message); 
         }
         case 2:
@@ -132,10 +147,15 @@ static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMe
     }
     if (type == TestMessageA::Type) {
         return firstMessage.value<TestMessageA>() == secondMessage.value<TestMessageA>();
+    
     } else if (type == TestMessageB::Type) {
-        return firstMessage.value<TestMessageB>() == secondMessage.value<TestMessageB>();
+        TestMessageB first = firstMessage.value<TestMessageB>();
+        TestMessageB second = secondMessage.value<TestMessageB>();
+        return first.foo == second.foo && equals(first.bar, second.bar);
+        
     } else if (type == TestMessageC::Type) {
         return firstMessage.value<TestMessageC>() == secondMessage.value<TestMessageC>();
+    
     } else {
         return firstMessage == secondMessage;
     }
@@ -277,3 +297,26 @@ void Endpoint::readReliableChannel() {
     }
     streamedBytesReceived += bytes.size();
 }
+
+TestSharedObjectA::TestSharedObjectA(float foo) :
+        _foo(foo) {
+    sharedObjectsCreated++;    
+}
+
+TestSharedObjectA::~TestSharedObjectA() {
+    sharedObjectsDestroyed++;
+}
+
+void TestSharedObjectA::setFoo(float foo) {
+    if (_foo != foo) {
+        emit fooChanged(_foo = foo);
+    }
+}
+
+TestSharedObjectB::TestSharedObjectB() {
+    sharedObjectsCreated++;
+}
+
+TestSharedObjectB::~TestSharedObjectB() {
+    sharedObjectsDestroyed++;
+}
diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h
index f19870ac15..3b69c28f79 100644
--- a/tests/metavoxels/src/MetavoxelTests.h
+++ b/tests/metavoxels/src/MetavoxelTests.h
@@ -64,6 +64,38 @@ private:
     CircularBuffer _dataStreamed;
 };
 
+/// A simple shared object.
+class TestSharedObjectA : public SharedObject {
+    Q_OBJECT
+    Q_PROPERTY(float foo READ getFoo WRITE setFoo NOTIFY fooChanged)
+
+public:
+    
+    Q_INVOKABLE TestSharedObjectA(float foo = 0.0f);
+    virtual ~TestSharedObjectA();
+
+    void setFoo(float foo);
+    float getFoo() const { return _foo; }
+
+signals:
+    
+    void fooChanged(float foo);    
+    
+private:
+    
+    float _foo;
+};
+
+/// Another simple shared object.
+class TestSharedObjectB : public SharedObject {
+    Q_OBJECT
+
+public:
+    
+    Q_INVOKABLE TestSharedObjectB();
+    virtual ~TestSharedObjectB();
+};
+
 /// A simple test message.
 class TestMessageA {
     STREAMABLE
@@ -84,6 +116,7 @@ class TestMessageB {
 public:
     
     STREAM QByteArray foo;
+    STREAM SharedObjectPointer bar;
 };
 
 DECLARE_STREAMABLE_METATYPE(TestMessageB)