diff --git a/src/objects.ts b/src/objects.ts
index c0b1a53ac39d27f4052f99ade10a98c787ab738b..3a0c998b080c8c06f9fbebe2de5d402b17ca72b9 100644
--- a/src/objects.ts
+++ b/src/objects.ts
@@ -25,6 +25,8 @@ export interface SpinaClass {
     prototype: object;
     __spinaOptions: SubclassOptions;
 
+    extend(protoProps, staticProps);
+
     readonly __spinaObjectID: number;
     readonly __super__: SpinaClass;
 }
@@ -221,7 +223,7 @@ function _automergeAttr(
  *     ``true`` if an attribute was copied. ``false`` if it was not.
  */
 function _copyPrototypeAttr(
-    cls: object,
+    cls: PartialSpinaClass,
     clsProto: object,
     attr: string,
 ): boolean {
@@ -265,6 +267,11 @@ function _prepareSubclass(
     const clsProto = cls.prototype;
     const mergeOptions: SubclassOptions = {};
 
+    if (options.mixins) {
+        /** Apply any mixins to the subclass. */
+        applyMixins(cls, options.mixins);
+    }
+
     /*
      * For any auto-extended static attributes set on both the parent class
      * and the decorated class, apply a `_.defaults(...)` to the attributes.
@@ -365,7 +372,6 @@ function _prepareSubclass(
             for (const attr of options.prototypeAttrs) {
                 if (!seen[attr] && _copyPrototypeAttr(cls, clsProto, attr)) {
                     /* The attribute has been copied. */
-                    clsProto[attr] = cls[attr];
                     seenClassAttrs.push(attr);
                 }
             }
@@ -384,11 +390,6 @@ function _prepareSubclass(
         }
     }
 
-    if (options.mixins) {
-        /** Apply any mixins to the subclass. */
-        applyMixins(cls, options.mixins);
-    }
-
     if (options && parentOptions) {
         /*
          * Merge in any parent options, so they'll apply to subclasses.
@@ -755,9 +756,9 @@ function _makeSpinaSubclass<TBase extends Class & SpinaClass>(
                  */
                 if (target === cls && this['initObject']) {
                     /*
-                     * This is the object being created, and we're at the tail end
-                     * of the constructor chain. We can now initialize the object
-                     * state.
+                     * This is the object being created, and we're at the tail
+                     * end of the constructor chain. We can now initialize the
+                     * object state.
                      */
                     this['initObject'](...args);
                 }
@@ -838,7 +839,8 @@ export function spinaSubclass<TBase extends Class & SpinaClass>(
  *
  * Version Changed:
  *     2.0:
- *     Added support for passing in plain objects to merge in.
+ *     * Added support for passing in plain objects to merge in.
+ *     * Static members of ES6 classes are now mixed in to the class body.
  *
  * Args:
  *     target (function):
@@ -857,10 +859,23 @@ export function applyMixins(
         const mixinBody = mixin['prototype'] || mixin;
 
         for (const name of Object.getOwnPropertyNames(mixinBody)) {
-            Object.defineProperty(
-                targetProto,
-                name,
-                Object.getOwnPropertyDescriptor(mixinBody, name) || {});
+            if (name !== 'prototype') {
+                Object.defineProperty(
+                    targetProto,
+                    name,
+                    Object.getOwnPropertyDescriptor(mixinBody, name) || {});
+            }
+        }
+
+        if (mixinBody !== mixin) {
+            for (const name of Object.getOwnPropertyNames(mixin)) {
+                if (name !== 'prototype') {
+                    Object.defineProperty(
+                        target,
+                        name,
+                        Object.getOwnPropertyDescriptor(mixin, name) || {});
+                }
+            }
         }
     }
 }
diff --git a/src/tests/spinaBaseClassExtendsTests.ts b/src/tests/spinaBaseClassExtendsTests.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7b9b07b33e85accde62d8212879c6d4a1cfec71c
--- /dev/null
+++ b/src/tests/spinaBaseClassExtendsTests.ts
@@ -0,0 +1,295 @@
+import 'jasmine';
+import Backbone from 'backbone';
+
+import { Class, spina, spinaBaseClassExtends } from '../index';
+
+
+class RealBaseClass {
+    static myAttrNum: number = 123;
+
+    static myAttrHash: object = {
+        'key1': 'value1',
+        'key2': 'value2',
+    };
+
+    static myStaticFunc() {
+        return 42;
+    }
+
+    constructor(...args: any[]) {
+        throw Error('Should not be executed.');
+    }
+
+    myFunc(): string {
+        return 'test';
+    }
+};
+
+
+describe('spinaBaseClassExtends', () => {
+    describe('Decorating class', () => {
+        it('Basic usage', () => {
+            abstract class MyBase extends spinaBaseClassExtends(
+                RealBaseClass,
+            ) {
+            }
+
+            expect(MyBase.__spinaObjectID).toBeDefined();
+            expect(MyBase.__spinaOptions).toEqual({});
+            expect(MyBase.name).toBe('MyBase');
+            expect(MyBase.myAttrNum).toBe(123);
+            expect(MyBase.myAttrHash).toEqual({
+                'key1': 'value1',
+                'key2': 'value2',
+            });
+
+            const proto = MyBase.prototype;
+            expect(proto['__spinaObjectID']).toBeUndefined();
+            expect(proto['myAttrNum']).toBeUndefined();
+            expect(proto['myAttrHash']).toBeUndefined();
+
+            const wrapperProto = Object.getPrototypeOf(MyBase);
+            expect(wrapperProto.name).toBe('RealBaseClass');
+            expect(Object.getPrototypeOf(wrapperProto)).toBe(RealBaseClass);
+        });
+
+        it('With anonymous base class', () => {
+            abstract class MyBase extends spinaBaseClassExtends(class {}) {
+            }
+
+            expect(MyBase.__spinaObjectID).toBeDefined();
+            expect(MyBase.__spinaOptions).toEqual({});
+            expect(MyBase.name).toBe('MyBase');
+
+            const proto = MyBase.prototype;
+            expect(proto['__spinaObjectID']).toBeUndefined();
+
+            const wrapperProto = Object.getPrototypeOf(MyBase);
+            expect(wrapperProto.name).toBe(
+                `_SpinaBaseClass${MyBase.__spinaObjectID}`);
+        });
+
+        it('With initObject on base', () => {
+            abstract class MyBase extends spinaBaseClassExtends(
+                RealBaseClass,
+            ) {
+                initArgs: any[];
+
+                initObject(...args: any[]) {
+                    this.initArgs = args;
+                }
+            }
+
+            @spina
+            class MyClass extends MyBase {}
+
+            const instance = new MyClass(1, 2, 3);
+            expect(instance.initArgs).toEqual([1, 2, 3]);
+        });
+
+        it('With options.automergeAttrs', () => {
+            abstract class MyBase extends spinaBaseClassExtends(
+                RealBaseClass,
+                {
+                    automergeAttrs: ['myAttrHash'],
+                },
+            ) {
+                static myAttrHash: object = {
+                    'a': 1,
+                    'b': 2,
+                };
+            }
+
+            expect(MyBase.__spinaOptions).toEqual({
+                automergeAttrs: ['myAttrHash'],
+            });
+
+            @spina
+            class MyClass1 extends MyBase {
+                static myAttrHash: object = {
+                    'c': 3,
+                    'd': 4,
+                };
+            }
+
+            expect(MyClass1.__spinaOptions).toEqual({
+                automergeAttrs: ['myAttrHash'],
+            });
+
+            @spina
+            class MyClass2 extends MyClass1 {
+                static myAttrHash: object = {
+                    'e': 5,
+                    'f': 6,
+                };
+            }
+
+            expect(MyClass1.myAttrHash).toEqual({
+                'a': 1,
+                'b': 2,
+                'c': 3,
+                'd': 4,
+            });
+
+            expect(MyClass2.myAttrHash).toEqual({
+                'a': 1,
+                'b': 2,
+                'c': 3,
+                'd': 4,
+                'e': 5,
+                'f': 6,
+            });
+        });
+
+        it('With options.initObject', () => {
+            abstract class MyBase extends spinaBaseClassExtends(
+                RealBaseClass,
+                {
+                    initObject(...args: any[]) {
+                        this.initArgs = args;
+                    }
+                }
+            ) {
+                initArgs: any[];
+            }
+
+            @spina
+            class MyClass extends MyBase {}
+
+            const instance = new MyClass(1, 2, 3);
+            expect(instance.initArgs).toEqual([1, 2, 3]);
+        });
+
+        it('With options.mixins=', () => {
+            abstract class MyBase extends spinaBaseClassExtends(
+                RealBaseClass,
+                {
+                    mixins: [
+                        /* A simple object mixin. */
+                        {
+                            mixedInAttr1: true,
+                            mixedInFunc1() {
+                                return 123;
+                            }
+                        },
+
+                        /* A prototype mixin. */
+                        Backbone.Model.extend({
+                            mixedInAttr2: 123,
+                            mixedInFunc2: function() {
+                                return 'test';
+                            },
+                        }),
+
+                        /* A class mixin. */
+                        class {
+                            static mixedInAttr3 = 'attr3';
+                            mixedInFunc3() {
+                                return true;
+                            }
+                        },
+                    ]
+                }
+            ) {
+            }
+
+            const proto = MyBase.prototype;
+            expect(proto['mixedInAttr1']).toBeTrue();
+            expect(proto['mixedInAttr2']).toBe(123);
+            expect(proto['mixedInFunc1']).toBeInstanceOf(Function);
+            expect(proto['mixedInFunc2']).toBeInstanceOf(Function);
+            expect(proto['mixedInFunc3']).toBeInstanceOf(Function);
+            expect(MyBase['mixedInAttr3']).toBe('attr3');
+        });
+
+        it('With options.name=', () => {
+            abstract class MyBase extends spinaBaseClassExtends(
+                RealBaseClass,
+                {
+                    name: 'CustomBase',
+                }
+            ) {
+            }
+
+            expect(MyBase.__spinaObjectID).toBeDefined();
+            expect(MyBase.__spinaOptions).toEqual({
+                name: 'CustomBase',
+            });
+            expect(MyBase.name).toBe('MyBase');
+            expect(MyBase.myAttrNum).toBe(123);
+            expect(MyBase.myAttrHash).toEqual({
+                'key1': 'value1',
+                'key2': 'value2',
+            });
+
+            const wrapperProto = Object.getPrototypeOf(MyBase);
+            expect(wrapperProto.name).toBe('CustomBase');
+            expect(Object.getPrototypeOf(wrapperProto)).toBe(RealBaseClass);
+        });
+
+        it('With options.prototypeAttrs=', () => {
+            abstract class MyBase extends spinaBaseClassExtends(
+                RealBaseClass,
+                {
+                    prototypeAttrs: [
+                        'myAttrNum',
+                        'myAttrHash',
+                        'myStaticFunc',
+                    ],
+                }
+            ) {
+            }
+
+            const wrapperProto = Object.getPrototypeOf(MyBase);
+
+            expect(wrapperProto.__spinaOptions).toEqual({
+                prototypeAttrs: [
+                    'myAttrNum',
+                    'myAttrHash',
+                    'myStaticFunc',
+                ],
+            });
+
+            expect(wrapperProto.myAttrNum).toBe(123);
+            expect(wrapperProto.myAttrHash).toEqual({
+                'key1': 'value1',
+                'key2': 'value2',
+            });
+            expect(wrapperProto.myStaticFunc).toBeInstanceOf(Function);
+        });
+    });
+
+    it('extend', () => {
+        abstract class MyBase extends spinaBaseClassExtends(RealBaseClass) {
+        }
+
+        const MyProto = MyBase.extend({
+            myNewAttr1: 123,
+            myNewAttr2: true,
+
+            myNewFunc: function() {
+            }
+        }, {
+            myStatic1: 'test',
+            myStatic2: [1, 2, 3],
+        });
+
+        expect(MyProto.myStatic1).toBe('test');
+        expect(MyProto.myStatic2).toEqual([1, 2, 3]);
+        expect(MyProto.myAttrNum).toBe(123);
+        expect(MyProto.myAttrHash).toEqual({
+            'key1': 'value1',
+            'key2': 'value2',
+        });
+        expect(MyProto.myStaticFunc).toBeInstanceOf(Function);
+
+        const proto = MyProto.prototype;
+        expect(proto.myNewAttr1).toBe(123);
+        expect(proto.myNewAttr2).toBeTrue();
+        expect(proto.myNewFunc).toBeInstanceOf(Function);
+        expect(proto.myFunc).toBeInstanceOf(Function);
+
+        const wrappedProto = Object.getPrototypeOf(MyProto);
+        expect(Object.getPrototypeOf(wrappedProto)).toBe(MyBase);
+    });
+});
