diff --git a/ember-data-types/q/record-data-json-api.ts b/ember-data-types/q/record-data-json-api.ts
index e87583c2379..5665d55091e 100644
--- a/ember-data-types/q/record-data-json-api.ts
+++ b/ember-data-types/q/record-data-json-api.ts
@@ -1,4 +1,4 @@
-import type { CollectionResourceRelationship, SingleResourceRelationship } from './ember-data-json-api';
+import type { CollectionResourceRelationship, Links, Meta, SingleResourceRelationship } from './ember-data-json-api';
 import type { Dict } from './utils';
 
 /**
@@ -10,12 +10,11 @@ export type AttributesHash = Dict<unknown>;
 export interface JsonApiResource {
   id?: string | null;
   type?: string;
-  attributes?: AttributesHash;
-  relationships?: {
-    [key: string]: SingleResourceRelationship | CollectionResourceRelationship;
-  };
-  meta?: any;
   lid?: string;
+  attributes?: AttributesHash;
+  relationships?: Dict<SingleResourceRelationship | CollectionResourceRelationship>;
+  meta?: Meta;
+  links?: Links;
 }
 
 export interface JsonApiValidationError {
diff --git a/ember-data-types/q/record-data-record-wrapper.ts b/ember-data-types/q/record-data-record-wrapper.ts
index 25bd5b5b20d..8b0241ea189 100644
--- a/ember-data-types/q/record-data-record-wrapper.ts
+++ b/ember-data-types/q/record-data-record-wrapper.ts
@@ -30,12 +30,7 @@ export interface RecordDataRecordWrapper {
   hasAttr(key: string): boolean;
 
   // new
-  getErrors?(recordIdentifier: RecordIdentifier): JsonApiValidationError[];
-  /**
-   * @internal
-   * @deprecated
-   */
-  getErrors?({}): JsonApiValidationError[]; // eslint-disable-line no-empty-pattern
+  getErrors(recordIdentifier: RecordIdentifier): JsonApiValidationError[];
 
   isNew?(): boolean;
   isDeleted?(): boolean;
diff --git a/ember-data-types/q/record-data.ts b/ember-data-types/q/record-data.ts
index 6b17bd38e5f..097a24ab7db 100644
--- a/ember-data-types/q/record-data.ts
+++ b/ember-data-types/q/record-data.ts
@@ -53,12 +53,7 @@ export interface RecordData {
   _initRecordCreateOptions(options: any): { [key: string]: unknown };
 
   // new
-  getErrors?(recordIdentifier: RecordIdentifier): JsonApiValidationError[];
-  /**
-   * @deprecated
-   * @internal
-   */
-  getErrors?({}): JsonApiValidationError[]; // eslint-disable-line no-empty-pattern
+  getErrors(recordIdentifier: RecordIdentifier): JsonApiValidationError[];
 
   isNew?(): boolean;
   isDeleted?(): boolean;
diff --git a/packages/-ember-data/tests/deprecations/deprecate-helpers-test.js b/packages/-ember-data/tests/deprecations/deprecate-helpers-test.js
new file mode 100644
index 00000000000..e3b09457598
--- /dev/null
+++ b/packages/-ember-data/tests/deprecations/deprecate-helpers-test.js
@@ -0,0 +1,48 @@
+import { module } from 'qunit';
+
+import { setupTest } from 'ember-qunit';
+
+import { errorsArrayToHash, errorsHashToArray } from '@ember-data/adapter/error';
+import { normalizeModelName } from '@ember-data/store';
+import { normalizeModelName as _privateNormalize } from '@ember-data/store/-private';
+import { deprecatedTest } from '@ember-data/unpublished-test-infra/test-support/deprecated-test';
+
+module('Deprecations', function (hooks) {
+  setupTest(hooks);
+
+  deprecatedTest(
+    `Calling normalizeModelName`,
+    { id: 'ember-data:deprecate-normalize-modelname-helper', until: '5.0', count: 1 },
+    function (assert) {
+      normalizeModelName('user');
+      assert.ok(true);
+    }
+  );
+
+  deprecatedTest(
+    `Calling normalizeModelName imported from private`,
+    { id: 'ember-data:deprecate-normalize-modelname-helper', until: '5.0', count: 1 },
+    function (assert) {
+      _privateNormalize('user');
+      assert.ok(true);
+    }
+  );
+
+  deprecatedTest(
+    `Calling errorsArrayToHash`,
+    { id: 'ember-data:deprecate-errors-array-to-hash-helper', until: '5.0', count: 1 },
+    function (assert) {
+      errorsArrayToHash([]);
+      assert.ok(true);
+    }
+  );
+
+  deprecatedTest(
+    `Calling errorsHashToArray`,
+    { id: 'ember-data:deprecate-errors-hash-to-array-helper', until: '5.0', count: 1 },
+    function (assert) {
+      errorsHashToArray({});
+      assert.ok(true);
+    }
+  );
+});
diff --git a/packages/-ember-data/tests/integration/adapter/client-side-delete-test.js b/packages/-ember-data/tests/integration/adapter/client-side-delete-test.js
index 6a8d6b56f6c..c44ef0912b9 100644
--- a/packages/-ember-data/tests/integration/adapter/client-side-delete-test.js
+++ b/packages/-ember-data/tests/integration/adapter/client-side-delete-test.js
@@ -12,7 +12,7 @@ module('integration/adapter/store-adapter - client-side delete', function (hooks
 
   test('client-side deleted records can be added back from an inverse', async function (assert) {
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     class Bookstore extends Model {
       @attr name;
diff --git a/packages/-ember-data/tests/integration/adapter/find-all-test.js b/packages/-ember-data/tests/integration/adapter/find-all-test.js
index 52a48afa257..12e6853b56e 100644
--- a/packages/-ember-data/tests/integration/adapter/find-all-test.js
+++ b/packages/-ember-data/tests/integration/adapter/find-all-test.js
@@ -32,7 +32,7 @@ module('integration/adapter/find-all - Finding All Records of a Type', function
     let { owner } = this;
 
     owner.register('model:person', Person);
-    owner.register('serializer:application', JSONAPISerializer.extend());
+    owner.register('serializer:application', class extends JSONAPISerializer {});
 
     store = owner.lookup('service:store');
   });
diff --git a/packages/-ember-data/tests/integration/adapter/find-test.js b/packages/-ember-data/tests/integration/adapter/find-test.js
index 098badd1ddc..8a7629f258b 100644
--- a/packages/-ember-data/tests/integration/adapter/find-test.js
+++ b/packages/-ember-data/tests/integration/adapter/find-test.js
@@ -18,7 +18,7 @@ module('integration/adapter/find - Finding Records', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     const store = this.owner.lookup('service:store');
 
@@ -40,7 +40,7 @@ module('integration/adapter/find - Finding Records', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let count = 0;
 
@@ -64,7 +64,7 @@ module('integration/adapter/find - Finding Records', function (hooks) {
         },
       })
     );
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     const store = this.owner.lookup('service:store');
 
@@ -79,7 +79,7 @@ module('integration/adapter/find - Finding Records', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let resolveFindRecordPromise;
     let findRecordPromise = new Promise((resolve) => (resolveFindRecordPromise = resolve));
@@ -125,7 +125,7 @@ module('integration/adapter/find - Finding Records', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register(
       'adapter:person',
       Adapter.extend({
@@ -152,7 +152,7 @@ module('integration/adapter/find - Finding Records', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register(
       'adapter:person',
       Adapter.extend({
@@ -180,7 +180,7 @@ module('integration/adapter/find - Finding Records', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register(
       'adapter:person',
       Adapter.extend({
@@ -208,7 +208,7 @@ module('integration/adapter/find - Finding Records', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register(
       'adapter:person',
       Adapter.extend({
@@ -237,7 +237,7 @@ module('integration/adapter/find - Finding Records', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register(
       'adapter:person',
       Adapter.extend({
@@ -269,7 +269,7 @@ module('integration/adapter/find - Finding Records', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register(
       'serializer:application',
       JSONAPISerializer.extend({
diff --git a/packages/-ember-data/tests/integration/adapter/json-api-adapter-test.js b/packages/-ember-data/tests/integration/adapter/json-api-adapter-test.js
index c60413a98c7..87397505871 100644
--- a/packages/-ember-data/tests/integration/adapter/json-api-adapter-test.js
+++ b/packages/-ember-data/tests/integration/adapter/json-api-adapter-test.js
@@ -1,10 +1,11 @@
 import { module, test } from 'qunit';
 import { resolve } from 'rsvp';
 
-import DS from 'ember-data';
 import { setupTest } from 'ember-qunit';
 
+import JSONAPIAdapter from '@ember-data/adapter/json-api';
 import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
+import JSONAPISerializer from '@ember-data/serializer/json-api';
 import testInDebug from '@ember-data/unpublished-test-infra/test-support/test-in-debug';
 
 let store, adapter;
@@ -58,8 +59,8 @@ module('integration/adapter/json-api-adapter - JSONAPIAdapter', function (hooks)
       @attr('number') hipsters;
     }
 
-    this.owner.register('adapter:application', DS.JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', DS.JSONAPISerializer.extend());
+    this.owner.register('adapter:application', class extends JSONAPIAdapter {});
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     this.owner.register('model:user', User);
     this.owner.register('model:post', Post);
@@ -922,11 +923,11 @@ module('integration/adapter/json-api-adapter - JSONAPIAdapter', function (hooks)
 
     this.owner.register(
       'serializer:user',
-      DS.JSONAPISerializer.extend({
-        attrs: {
+      class extends JSONAPISerializer {
+        attrs = {
           handles: { serialize: true },
-        },
-      })
+        };
+      }
     );
 
     let user = store.push({
diff --git a/packages/-ember-data/tests/integration/adapter/queries-test.js b/packages/-ember-data/tests/integration/adapter/queries-test.js
index 8cef37d8f6c..a93a527059d 100644
--- a/packages/-ember-data/tests/integration/adapter/queries-test.js
+++ b/packages/-ember-data/tests/integration/adapter/queries-test.js
@@ -15,7 +15,7 @@ module('integration/adapter/queries - Queries', function (hooks) {
 
   hooks.beforeEach(function () {
     this.owner.register('adapter:application', JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   testInDebug('It raises an assertion when no type is passed', function (assert) {
diff --git a/packages/-ember-data/tests/integration/adapter/record-persistence-test.js b/packages/-ember-data/tests/integration/adapter/record-persistence-test.js
index a65c9da3573..96e4bb5c4b1 100644
--- a/packages/-ember-data/tests/integration/adapter/record-persistence-test.js
+++ b/packages/-ember-data/tests/integration/adapter/record-persistence-test.js
@@ -26,7 +26,7 @@ module('integration/adapter/record_persistence - Persisting Records', function (
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
     let adapter = store.adapterFor('application');
@@ -70,7 +70,7 @@ module('integration/adapter/record_persistence - Persisting Records', function (
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
     let adapter = store.adapterFor('application');
@@ -106,7 +106,7 @@ module('integration/adapter/record_persistence - Persisting Records', function (
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
     let adapter = store.adapterFor('application');
@@ -140,7 +140,7 @@ module('integration/adapter/record_persistence - Persisting Records', function (
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
     let adapter = store.adapterFor('application');
@@ -186,7 +186,7 @@ module('integration/adapter/record_persistence - Persisting Records', function (
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
     let adapter = store.adapterFor('application');
@@ -283,7 +283,7 @@ module('integration/adapter/record_persistence - Persisting Records', function (
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
     let adapter = store.adapterFor('application');
diff --git a/packages/-ember-data/tests/integration/adapter/serialize-test.js b/packages/-ember-data/tests/integration/adapter/serialize-test.js
index ed325c9ca8d..26df9512339 100644
--- a/packages/-ember-data/tests/integration/adapter/serialize-test.js
+++ b/packages/-ember-data/tests/integration/adapter/serialize-test.js
@@ -16,7 +16,7 @@ module('integration/adapter/serialize - DS.Adapter integration test', function (
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
     let adapter = store.adapterFor('application');
diff --git a/packages/-ember-data/tests/integration/adapter/store-adapter-test.js b/packages/-ember-data/tests/integration/adapter/store-adapter-test.js
index 7441d0151ce..7e018b32ca2 100644
--- a/packages/-ember-data/tests/integration/adapter/store-adapter-test.js
+++ b/packages/-ember-data/tests/integration/adapter/store-adapter-test.js
@@ -21,8 +21,7 @@ function moveRecordOutOfInFlight(record) {
   let { store, _internalModel } = record;
   // TODO this would be made nicer by a cancellation API
   let pending = store.getRequestStateService().getPendingRequestsForRecord(_internalModel.identifier);
-  pending.splice(0, pending.length); // release the requests
-  _internalModel.adapterDidError(new Error());
+  pending.splice(0, pending.length);
 }
 
 module('integration/adapter/store-adapter - DS.Store and DS.Adapter integration test', function (hooks) {
@@ -39,7 +38,7 @@ module('integration/adapter/store-adapter - DS.Store and DS.Adapter integration
     }
 
     this.owner.register('adapter:application', JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register('model:person', Person);
     this.owner.register('model:dog', Dog);
   });
diff --git a/packages/-ember-data/tests/integration/backwards-compat/non-dasherized-lookups-test.js b/packages/-ember-data/tests/integration/backwards-compat/non-dasherized-lookups-test.js
index 29cd7a5d067..f042aa0729a 100644
--- a/packages/-ember-data/tests/integration/backwards-compat/non-dasherized-lookups-test.js
+++ b/packages/-ember-data/tests/integration/backwards-compat/non-dasherized-lookups-test.js
@@ -27,7 +27,7 @@ module(
 
       this.owner.register('model:post-note', PostNote);
       this.owner.register('adapter:application', ApplicationAdapter);
-      this.owner.register('serializer:application', JSONAPISerializer.extend());
+      this.owner.register('serializer:application', class extends JSONAPISerializer {});
     });
 
     test('can lookup records using camelCase strings', function (assert) {
@@ -110,7 +110,7 @@ module(
       this.owner.register('model:note-post', NotePost);
       this.owner.register('model:post-note', PostNote);
       this.owner.register('adapter:application', ApplicationAdapter);
-      this.owner.register('serializer:application', JSONAPISerializer.extend());
+      this.owner.register('serializer:application', class extends JSONAPISerializer {});
     });
 
     test('looks up belongsTo using camelCase strings', function (assert) {
diff --git a/packages/-ember-data/tests/integration/client-id-generation-test.js b/packages/-ember-data/tests/integration/client-id-generation-test.js
index 059bae6d8e6..5f4e857442e 100644
--- a/packages/-ember-data/tests/integration/client-id-generation-test.js
+++ b/packages/-ember-data/tests/integration/client-id-generation-test.js
@@ -38,7 +38,7 @@ module('integration - Client Id Generation', function (hooks) {
     owner.register('model:post', Post);
     owner.register('model:misc', Misc);
     owner.register('adapter:application', JSONAPIAdapter.extend());
-    owner.register('serializer:application', JSONAPISerializer.extend());
+    owner.register('serializer:application', class extends JSONAPISerializer {});
 
     store = owner.lookup('service:store');
     adapter = store.adapterFor('application');
diff --git a/packages/-ember-data/tests/integration/identifiers/configuration-test.ts b/packages/-ember-data/tests/integration/identifiers/configuration-test.ts
index aca1153f290..82316c95d29 100644
--- a/packages/-ember-data/tests/integration/identifiers/configuration-test.ts
+++ b/packages/-ember-data/tests/integration/identifiers/configuration-test.ts
@@ -33,7 +33,7 @@ module('Integration | Identifiers - configuration', function (hooks) {
     const { owner } = this;
 
     owner.register('adapter:application', JSONAPIAdapter.extend());
-    owner.register('serializer:application', JSONAPISerializer.extend());
+    owner.register('serializer:application', class extends JSONAPISerializer {});
     class User extends Model {
       @attr()
       declare firstName: string;
diff --git a/packages/-ember-data/tests/integration/record-array-test.js b/packages/-ember-data/tests/integration/record-array-test.js
index 4ca856cf62e..62a19fefb09 100644
--- a/packages/-ember-data/tests/integration/record-array-test.js
+++ b/packages/-ember-data/tests/integration/record-array-test.js
@@ -39,7 +39,7 @@ module('unit/record-array - RecordArray', function (hooks) {
     owner.register('model:tag', Tag);
     owner.register('model:tool', Tool);
     owner.register('adapter:application', JSONAPIAdapter.extend());
-    owner.register('serializer:application', JSONAPISerializer.extend());
+    owner.register('serializer:application', class extends JSONAPISerializer {});
 
     store = owner.lookup('service:store');
   });
diff --git a/packages/-ember-data/tests/integration/record-arrays/adapter-populated-record-array-test.js b/packages/-ember-data/tests/integration/record-arrays/adapter-populated-record-array-test.js
index a7647a8390a..7cff8970f4e 100644
--- a/packages/-ember-data/tests/integration/record-arrays/adapter-populated-record-array-test.js
+++ b/packages/-ember-data/tests/integration/record-arrays/adapter-populated-record-array-test.js
@@ -24,7 +24,7 @@ module('integration/record-arrays/adapter_populated_record_array - AdapterPopula
   hooks.beforeEach(function () {
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('when a record is deleted in an adapter populated record array, it should be removed', async function (assert) {
diff --git a/packages/-ember-data/tests/integration/record-data/record-data-errors-test.ts b/packages/-ember-data/tests/integration/record-data/record-data-errors-test.ts
index 5216991a255..2283f3bbab4 100644
--- a/packages/-ember-data/tests/integration/record-data/record-data-errors-test.ts
+++ b/packages/-ember-data/tests/integration/record-data/record-data-errors-test.ts
@@ -9,7 +9,7 @@ import { InvalidError } from '@ember-data/adapter/error';
 import Model, { attr } from '@ember-data/model';
 import JSONAPISerializer from '@ember-data/serializer/json-api';
 import Store from '@ember-data/store';
-import type { NewRecordIdentifier, RecordIdentifier } from '@ember-data/types/q/identifier';
+import type { NewRecordIdentifier, RecordIdentifier, StableRecordIdentifier } from '@ember-data/types/q/identifier';
 import type { RecordData } from '@ember-data/types/q/record-data';
 import type { JsonApiValidationError } from '@ember-data/types/q/record-data-json-api';
 
@@ -37,7 +37,13 @@ class TestRecordData implements RecordData {
     }
   }
 
-  commitWasRejected(recordIdentifier: RecordIdentifier, errors?: JsonApiValidationError[]): void {}
+  _errors: JsonApiValidationError[] = [];
+  getErrors(recordIdentifier: RecordIdentifier): JsonApiValidationError[] {
+    return this._errors;
+  }
+  commitWasRejected(identifier: StableRecordIdentifier, errors: JsonApiValidationError[]): void {
+    this._errors = errors;
+  }
 
   // Use correct interface once imports have been fix
   _storeWrapper: any;
@@ -142,6 +148,7 @@ module('integration/record-data - Custom RecordData Errors', function (hooks) {
 
     class LifecycleRecordData extends TestRecordData {
       commitWasRejected(recordIdentifier, errors) {
+        super.commitWasRejected(recordIdentifier, errors);
         assert.strictEqual(errors[0].detail, 'is a generally unsavoury character', 'received the error');
         assert.strictEqual(errors[0].source.pointer, '/data/attributes/name', 'pointer is correct');
       }
@@ -201,6 +208,7 @@ module('integration/record-data - Custom RecordData Errors', function (hooks) {
 
     class LifecycleRecordData extends TestRecordData {
       commitWasRejected(recordIdentifier, errors) {
+        super.commitWasRejected(recordIdentifier, errors);
         assert.strictEqual(errors, undefined, 'Did not pass adapter errors');
       }
     }
@@ -300,68 +308,4 @@ module('integration/record-data - Custom RecordData Errors', function (hooks) {
     let lastNameError = person.get('errors').errorsFor('lastName').get('firstObject');
     assert.strictEqual(lastNameError.attribute, 'lastName', 'error shows up on lastName');
   });
-
-  test('Record data which does not implement getErrors still works correctly with the default DS.Model', async function (assert) {
-    assert.expect(4);
-
-    const personHash = {
-      type: 'person',
-      id: '1',
-      attributes: {
-        name: 'Scumbag Dale',
-      },
-    };
-    let { owner } = this;
-
-    class LifecycleRecordData extends TestRecordData {
-      commitWasRejected(recordIdentifier, errors) {
-        assert.strictEqual(errors[0].detail, 'is a generally unsavoury character', 'received the error');
-        assert.strictEqual(errors[0].source.pointer, '/data/attributes/name', 'pointer is correct');
-      }
-    }
-
-    let TestStore = Store.extend({
-      createRecordDataFor(modelName, id, clientId, storeWrapper) {
-        return new LifecycleRecordData();
-      },
-    });
-
-    let TestAdapter = EmberObject.extend({
-      updateRecord() {
-        return Promise.reject(
-          new InvalidError([
-            {
-              title: 'Invalid Attribute',
-              detail: 'is a generally unsavoury character',
-              source: {
-                pointer: '/data/attributes/name',
-              },
-            },
-          ])
-        );
-      },
-
-      createRecord() {
-        return Promise.resolve();
-      },
-    });
-
-    owner.register('service:store', TestStore);
-    owner.register('adapter:application', TestAdapter, { singleton: false });
-
-    store = owner.lookup('service:store');
-
-    store.push({
-      data: [personHash],
-    });
-    let person = store.peekRecord('person', '1');
-    await person.save().then(
-      () => {},
-      (err) => {}
-    );
-
-    assert.false(person.get('isValid'), 'rejecting the save invalidates the person');
-    let nameError = person.get('errors').errorsFor('name').get('firstObject');
-    assert.strictEqual(nameError.attribute, 'name', 'error shows up on name');
-  });
 });
diff --git a/packages/-ember-data/tests/integration/record-data/record-data-state-test.ts b/packages/-ember-data/tests/integration/record-data/record-data-state-test.ts
index 77cc7cf7d3c..911c09d8713 100644
--- a/packages/-ember-data/tests/integration/record-data/record-data-state-test.ts
+++ b/packages/-ember-data/tests/integration/record-data/record-data-state-test.ts
@@ -9,8 +9,9 @@ import { setupTest } from 'ember-qunit';
 import Model, { attr } from '@ember-data/model';
 import JSONAPISerializer from '@ember-data/serializer/json-api';
 import Store from '@ember-data/store';
-import type { NewRecordIdentifier } from '@ember-data/types/q/identifier';
+import type { NewRecordIdentifier, RecordIdentifier, StableRecordIdentifier } from '@ember-data/types/q/identifier';
 import type { RecordData } from '@ember-data/types/q/record-data';
+import { JsonApiValidationError } from '@ember-data/types/q/record-data-json-api';
 
 class Person extends Model {
   // TODO fix the typing for naked attrs
@@ -29,6 +30,13 @@ class TestRecordData implements RecordData {
   id: string | null = '1';
   clientId: string | null = 'test-record-data-1';
   modelName = 'tst';
+  _errors: JsonApiValidationError[] = [];
+  getErrors(recordIdentifier: RecordIdentifier): JsonApiValidationError[] {
+    return this._errors;
+  }
+  commitWasRejected(identifier: StableRecordIdentifier, errors: JsonApiValidationError[]): void {
+    this._errors = errors;
+  }
 
   getResourceIdentifier() {
     if (this.clientId !== null) {
@@ -36,8 +44,6 @@ class TestRecordData implements RecordData {
     }
   }
 
-  commitWasRejected(): void {}
-
   // Use correct interface once imports have been fix
   _storeWrapper: any;
 
diff --git a/packages/-ember-data/tests/integration/record-data/record-data-test.ts b/packages/-ember-data/tests/integration/record-data/record-data-test.ts
index fbb7668f612..d493bfecc07 100644
--- a/packages/-ember-data/tests/integration/record-data/record-data-test.ts
+++ b/packages/-ember-data/tests/integration/record-data/record-data-test.ts
@@ -10,6 +10,8 @@ import JSONAPIAdapter from '@ember-data/adapter/json-api';
 import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
 import JSONAPISerializer from '@ember-data/serializer/json-api';
 import Store from '@ember-data/store';
+import { StableRecordIdentifier } from '@ember-data/types/q/identifier';
+import { JsonApiValidationError } from '@ember-data/types/q/record-data-json-api';
 
 class Person extends Model {
   // TODO fix the typing for naked attrs
@@ -43,7 +45,13 @@ class TestRecordData {
 
   willCommit() {}
 
-  commitWasRejected() {}
+  _errors: JsonApiValidationError[] = [];
+  getErrors(recordIdentifier: StableRecordIdentifier): JsonApiValidationError[] {
+    return this._errors;
+  }
+  commitWasRejected(identifier: StableRecordIdentifier, errors: JsonApiValidationError[]): void {
+    this._errors = errors;
+  }
 
   unloadRecord() {}
   rollbackAttributes() {}
@@ -144,7 +152,7 @@ module('integration/record-data - Custom RecordData Implementations', function (
     owner.unregister('service:store');
     owner.register('service:store', CustomStore);
     owner.register('adapter:application', JSONAPIAdapter.extend());
-    owner.register('serializer:application', JSONAPISerializer.extend());
+    owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('A RecordData implementation that has the required spec methods should not error out', async function (assert) {
@@ -191,7 +199,7 @@ module('integration/record-data - Custom RecordData Implementations', function (
   });
 
   test('Record Data push, create and save lifecycle', async function (assert) {
-    assert.expect(17);
+    assert.expect(19);
     let called = 0;
     const personHash = {
       type: 'person',
@@ -226,7 +234,8 @@ module('integration/record-data - Custom RecordData Implementations', function (
         calledWillCommit++;
       }
 
-      commitWasRejected() {
+      commitWasRejected(identifier, errors) {
+        super.commitWasRejected(identifier, errors);
         calledWasRejected++;
       }
 
@@ -286,10 +295,11 @@ module('integration/record-data - Custom RecordData Implementations', function (
     await settled();
     assert.strictEqual(calledDidCommit, 1, 'Called didCommit');
 
-    person.save();
+    let promise = person.save();
     assert.strictEqual(calledWillCommit, 2, 'Called willCommit');
 
-    await settled();
+    await promise.catch((_e) => assert.ok(true, 'we erred'));
+
     assert.strictEqual(calledDidCommit, 1, 'Did not call didCommit again');
     assert.strictEqual(calledWasRejected, 1, 'Called commitWasRejected');
 
@@ -319,10 +329,10 @@ module('integration/record-data - Custom RecordData Implementations', function (
     await settled();
     assert.strictEqual(calledDidCommit, 1, 'Called didCommit');
 
-    clientPerson.save();
+    promise = clientPerson.save();
     assert.strictEqual(calledWillCommit, 2, 'Called willCommit');
 
-    await settled();
+    await promise.catch((_e) => assert.ok('we erred'));
     assert.strictEqual(calledWasRejected, 1, 'Called commitWasRejected');
     assert.strictEqual(calledDidCommit, 1, 'Did not call didCommit again');
 
diff --git a/packages/-ember-data/tests/integration/records/collection-save-test.js b/packages/-ember-data/tests/integration/records/collection-save-test.js
index a0d0cf6ba1c..f9130400594 100644
--- a/packages/-ember-data/tests/integration/records/collection-save-test.js
+++ b/packages/-ember-data/tests/integration/records/collection-save-test.js
@@ -19,7 +19,7 @@ module('integration/records/collection_save - Save Collection of Records', funct
 
     this.owner.register('model:post', Post);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('Collection will resolve save on success', function (assert) {
diff --git a/packages/-ember-data/tests/integration/records/delete-record-test.js b/packages/-ember-data/tests/integration/records/delete-record-test.js
index e030bc7c318..2daac4b483e 100644
--- a/packages/-ember-data/tests/integration/records/delete-record-test.js
+++ b/packages/-ember-data/tests/integration/records/delete-record-test.js
@@ -25,7 +25,7 @@ module('integration/deletedRecord - Deleting Records', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('records should not be removed from record arrays just after deleting, but only after committing them', async function (assert) {
diff --git a/packages/-ember-data/tests/integration/records/error-test.js b/packages/-ember-data/tests/integration/records/error-test.js
index a945ef6bd71..430fcc86fa8 100644
--- a/packages/-ember-data/tests/integration/records/error-test.js
+++ b/packages/-ember-data/tests/integration/records/error-test.js
@@ -20,7 +20,7 @@ module('integration/records/error', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -76,7 +76,7 @@ module('integration/records/error', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -125,7 +125,7 @@ module('integration/records/error', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -159,7 +159,7 @@ module('integration/records/error', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -192,7 +192,7 @@ module('integration/records/error', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
     let adapter = store.adapterFor('application');
diff --git a/packages/-ember-data/tests/integration/records/property-changes-test.js b/packages/-ember-data/tests/integration/records/property-changes-test.js
index c091f97c7a7..75ae309a0aa 100644
--- a/packages/-ember-data/tests/integration/records/property-changes-test.js
+++ b/packages/-ember-data/tests/integration/records/property-changes-test.js
@@ -20,7 +20,7 @@ module('integration/records/property-changes - Property changes', function (hook
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('Calling push with partial records trigger observers for just those attributes that changed', function (assert) {
diff --git a/packages/-ember-data/tests/integration/records/relationship-changes-test.js b/packages/-ember-data/tests/integration/records/relationship-changes-test.js
index 3c77ce582d5..3396170747f 100644
--- a/packages/-ember-data/tests/integration/records/relationship-changes-test.js
+++ b/packages/-ember-data/tests/integration/records/relationship-changes-test.js
@@ -104,7 +104,7 @@ module('integration/records/relationship-changes - Relationship changes', functi
     this.owner.register('model:post', Post);
 
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   if (!gte('4.0.0')) {
diff --git a/packages/-ember-data/tests/integration/records/rematerialize-test.js b/packages/-ember-data/tests/integration/records/rematerialize-test.js
index 4ed83dbf51b..2bdf32e3e4d 100644
--- a/packages/-ember-data/tests/integration/records/rematerialize-test.js
+++ b/packages/-ember-data/tests/integration/records/rematerialize-test.js
@@ -16,7 +16,7 @@ module('integration/unload - Rematerializing Unloaded Records', function (hooks)
 
   hooks.beforeEach(function () {
     this.owner.register('adapter:application', JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('a sync belongs to relationship to an unloaded record can restore that record', function (assert) {
diff --git a/packages/-ember-data/tests/integration/records/save-test.js b/packages/-ember-data/tests/integration/records/save-test.js
index 531e83eaf26..9e5111f574c 100644
--- a/packages/-ember-data/tests/integration/records/save-test.js
+++ b/packages/-ember-data/tests/integration/records/save-test.js
@@ -21,7 +21,7 @@ module('integration/records/save - Save Record', function (hooks) {
 
     this.owner.register('model:post', Post);
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('Will resolve save on success', async function (assert) {
diff --git a/packages/-ember-data/tests/integration/records/unload-test.js b/packages/-ember-data/tests/integration/records/unload-test.js
index 4c87f0c98d3..6e6b47b674b 100644
--- a/packages/-ember-data/tests/integration/records/unload-test.js
+++ b/packages/-ember-data/tests/integration/records/unload-test.js
@@ -136,7 +136,7 @@ module('integration/unload - Unloading Records', function (hooks) {
     owner.register(`model:spoon`, Spoon);
     owner.register(`model:show`, Show);
     owner.register('adapter:application', JSONAPIAdapter.extend());
-    owner.register('serializer:application', JSONAPISerializer.extend());
+    owner.register('serializer:application', class extends JSONAPISerializer {});
 
     store = owner.lookup('service:store');
     adapter = store.adapterFor('application');
diff --git a/packages/-ember-data/tests/integration/references/belongs-to-test.js b/packages/-ember-data/tests/integration/references/belongs-to-test.js
index 0a9c7d6e926..1d9a6461eac 100644
--- a/packages/-ember-data/tests/integration/references/belongs-to-test.js
+++ b/packages/-ember-data/tests/integration/references/belongs-to-test.js
@@ -28,7 +28,7 @@ module('integration/references/belongs-to', function (hooks) {
     this.owner.register('model:person', Person);
 
     this.owner.register('adapter:application', JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   testInDebug("record#belongsTo asserts when specified relationship doesn't exist", function (assert) {
diff --git a/packages/-ember-data/tests/integration/references/has-many-test.js b/packages/-ember-data/tests/integration/references/has-many-test.js
index 1bd6b81b040..ade9edae091 100755
--- a/packages/-ember-data/tests/integration/references/has-many-test.js
+++ b/packages/-ember-data/tests/integration/references/has-many-test.js
@@ -36,7 +36,7 @@ module('integration/references/has-many', function (hooks) {
     this.owner.register('model:pet', Pet);
 
     this.owner.register('adapter:application', DS.Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   testInDebug("record#hasMany asserts when specified relationship doesn't exist", function (assert) {
diff --git a/packages/-ember-data/tests/integration/references/record-test.js b/packages/-ember-data/tests/integration/references/record-test.js
index eacdaaf8f64..e866c7b751c 100644
--- a/packages/-ember-data/tests/integration/references/record-test.js
+++ b/packages/-ember-data/tests/integration/references/record-test.js
@@ -20,7 +20,7 @@ module('integration/references/record', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('a RecordReference can be retrieved via store.getReference(type, id)', function (assert) {
diff --git a/packages/-ember-data/tests/integration/relationships/belongs-to-test.js b/packages/-ember-data/tests/integration/relationships/belongs-to-test.js
index a7033416a88..09728cb189f 100644
--- a/packages/-ember-data/tests/integration/relationships/belongs-to-test.js
+++ b/packages/-ember-data/tests/integration/relationships/belongs-to-test.js
@@ -324,7 +324,7 @@ module('integration/relationship/belongs_to Belongs-To Relationships', function
     this.owner.register('model:section', Section);
 
     this.owner.register('adapter:application', JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     this.owner.register(
       'serializer:user',
diff --git a/packages/-ember-data/tests/integration/relationships/has-many-test.js b/packages/-ember-data/tests/integration/relationships/has-many-test.js
index 84c1379212e..f3294d653e2 100644
--- a/packages/-ember-data/tests/integration/relationships/has-many-test.js
+++ b/packages/-ember-data/tests/integration/relationships/has-many-test.js
@@ -84,7 +84,7 @@ module('integration/relationships/has_many - Has-Many Relationships', function (
     this.owner.register('model:page', Page);
 
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   testInDebug(
diff --git a/packages/-ember-data/tests/integration/relationships/json-api-links-test.js b/packages/-ember-data/tests/integration/relationships/json-api-links-test.js
index 35ef080730e..ccf48f82150 100644
--- a/packages/-ember-data/tests/integration/relationships/json-api-links-test.js
+++ b/packages/-ember-data/tests/integration/relationships/json-api-links-test.js
@@ -28,13 +28,13 @@ module('integration/relationship/json-api-links | Relationship state updates', f
     this.owner.register('model:user', User);
     this.owner.register('model:organisation', Organisation);
     this.owner.register('adapter:application', DS.Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
     this.owner.register(
       'adapter:user',
-      DS.JSONAPISerializer.extend({
+      class extends JSONAPISerializer {
         findRecord(store, type, id) {
           return resolve({
             data: {
@@ -47,13 +47,13 @@ module('integration/relationship/json-api-links | Relationship state updates', f
               },
             },
           });
-        },
-      })
+        }
+      }
     );
 
     this.owner.register(
       'adapter:organisation',
-      DS.JSONAPISerializer.extend({
+      class extends JSONAPISerializer {
         findRecord(store, type, id) {
           return resolve({
             data: {
@@ -68,8 +68,8 @@ module('integration/relationship/json-api-links | Relationship state updates', f
               },
             },
           });
-        },
-      })
+        }
+      }
     );
 
     return run(() => {
@@ -106,7 +106,7 @@ module('integration/relationship/json-api-links | Relationship state updates', f
     this.owner.register('model:child', Child);
     this.owner.register('model:parent', Parent);
     this.owner.register('adapter:application', DS.Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -179,7 +179,7 @@ module('integration/relationship/json-api-links | Relationship state updates', f
     this.owner.register('model:pet', Pet);
 
     this.owner.register('adapter:application', Adapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -265,7 +265,7 @@ module('integration/relationship/json-api-links | Relationship state updates', f
     this.owner.register('model:pet', Pet);
 
     this.owner.register('adapter:application', Adapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -350,7 +350,7 @@ module('integration/relationship/json-api-links | Relationship state updates', f
     this.owner.register('model:pet', Pet);
 
     this.owner.register('adapter:application', Adapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -437,7 +437,7 @@ module('integration/relationship/json-api-links | Relationship state updates', f
     this.owner.register('model:pet', Pet);
 
     this.owner.register('adapter:application', Adapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -526,7 +526,7 @@ module('integration/relationship/json-api-links | Relationship state updates', f
     this.owner.register('model:pet', Pet);
 
     this.owner.register('adapter:application', Adapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -597,7 +597,7 @@ module('integration/relationship/json-api-links | Relationship state updates', f
     this.owner.register('model:pet', Pet);
 
     this.owner.register('adapter:application', Adapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -667,7 +667,7 @@ module('integration/relationship/json-api-links | Relationship fetching', functi
     this.owner.register('model:home', Home);
 
     this.owner.register('adapter:application', JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   /*
diff --git a/packages/-ember-data/tests/integration/relationships/many-to-many-test.js b/packages/-ember-data/tests/integration/relationships/many-to-many-test.js
index 0e90b7c95e2..f49f8facd87 100644
--- a/packages/-ember-data/tests/integration/relationships/many-to-many-test.js
+++ b/packages/-ember-data/tests/integration/relationships/many-to-many-test.js
@@ -38,7 +38,7 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships',
     this.owner.register('model:account', Account);
 
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   /*
diff --git a/packages/-ember-data/tests/integration/relationships/one-to-many-test.js b/packages/-ember-data/tests/integration/relationships/one-to-many-test.js
index a8ab39bc976..0deb19ca591 100644
--- a/packages/-ember-data/tests/integration/relationships/one-to-many-test.js
+++ b/packages/-ember-data/tests/integration/relationships/one-to-many-test.js
@@ -39,7 +39,7 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', f
     this.owner.register('model:account', Account);
 
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   /*
diff --git a/packages/-ember-data/tests/integration/relationships/one-to-one-test.js b/packages/-ember-data/tests/integration/relationships/one-to-one-test.js
index 5040aa3d37f..d2239fcf01a 100644
--- a/packages/-ember-data/tests/integration/relationships/one-to-one-test.js
+++ b/packages/-ember-data/tests/integration/relationships/one-to-one-test.js
@@ -30,7 +30,7 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', fun
       deleteRecord: () => resolve(),
     });
 
-    const ApplicationSerializer = JSONAPISerializer.extend();
+    const ApplicationSerializer = class extends JSONAPISerializer {};
 
     this.owner.register('model:user', User);
     this.owner.register('model:job', Job);
diff --git a/packages/-ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/packages/-ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js
index b958ac6d71c..b2ae81e548c 100644
--- a/packages/-ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js
+++ b/packages/-ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js
@@ -36,7 +36,7 @@ module(
       this.owner.register('mixin:message', Message);
 
       this.owner.register('adapter:application', Adapter.extend());
-      this.owner.register('serializer:application', JSONAPISerializer.extend());
+      this.owner.register('serializer:application', class extends JSONAPISerializer {});
     });
 
     /*
diff --git a/packages/-ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/packages/-ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js
index 261e81caa00..07b3858c281 100644
--- a/packages/-ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js
+++ b/packages/-ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js
@@ -38,7 +38,7 @@ module(
       this.owner.register('mixin:message', Message);
 
       this.owner.register('adapter:application', Adapter.extend());
-      this.owner.register('serializer:application', JSONAPISerializer.extend());
+      this.owner.register('serializer:application', class extends JSONAPISerializer {});
     });
 
     /*
diff --git a/packages/-ember-data/tests/integration/serializers/json-api-serializer-test.js b/packages/-ember-data/tests/integration/serializers/json-api-serializer-test.js
index d0a53a8a0e8..81bad529623 100644
--- a/packages/-ember-data/tests/integration/serializers/json-api-serializer-test.js
+++ b/packages/-ember-data/tests/integration/serializers/json-api-serializer-test.js
@@ -6,6 +6,8 @@ import { module, test } from 'qunit';
 import DS from 'ember-data';
 import { setupTest } from 'ember-qunit';
 
+import JSONAPIAdapter from '@ember-data/adapter/json-api';
+import JSONAPISerializer from '@ember-data/serializer/json-api';
 import testInDebug from '@ember-data/unpublished-test-infra/test-support/test-in-debug';
 
 module('integration/serializers/json-api-serializer - JSONAPISerializer', function (hooks) {
@@ -49,8 +51,8 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
     this.owner.register('model:company', Company);
     this.owner.register('model:project', Project);
 
-    this.owner.register('adapter:application', DS.JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', DS.JSONAPISerializer.extend());
+    this.owner.register('adapter:application', class extends JSONAPIAdapter {});
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('Calling pushPayload works', function (assert) {
@@ -256,7 +258,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
   test('Serializer should respect the attrs hash when extracting attributes and relationships', function (assert) {
     this.owner.register(
       'serializer:user',
-      DS.JSONAPISerializer.extend({
+      JSONAPISerializer.extend({
         attrs: {
           firstName: 'firstname_attribute_key',
           title: 'title_attribute_key',
@@ -303,7 +305,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
   test('Serializer should respect the attrs hash when serializing attributes and relationships', function (assert) {
     this.owner.register(
       'serializer:user',
-      DS.JSONAPISerializer.extend({
+      JSONAPISerializer.extend({
         attrs: {
           firstName: 'firstname_attribute_key',
           title: 'title_attribute_key',
@@ -343,7 +345,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
   test('Serializer should respect the attrs hash when extracting attributes with not camelized keys', function (assert) {
     this.owner.register(
       'serializer:project',
-      DS.JSONAPISerializer.extend({
+      JSONAPISerializer.extend({
         attrs: {
           'company-name': 'company_name',
         },
@@ -371,7 +373,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
   test('Serializer should respect the attrs hash when serializing attributes with not camelized keys', function (assert) {
     this.owner.register(
       'serializer:project',
-      DS.JSONAPISerializer.extend({
+      JSONAPISerializer.extend({
         attrs: {
           'company-name': 'company_name',
         },
@@ -419,7 +421,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
 
   testInDebug('Warns when defining extractMeta()', function (assert) {
     assert.expectWarning(function () {
-      DS.JSONAPISerializer.extend({
+      JSONAPISerializer.extend({
         extractMeta() {},
       }).create();
     }, /You've defined 'extractMeta' in/);
@@ -506,7 +508,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
   test('it should serialize a hasMany relationship', function (assert) {
     this.owner.register(
       'serializer:user',
-      DS.JSONAPISerializer.extend({
+      JSONAPISerializer.extend({
         attrs: {
           handles: { serialize: true },
         },
@@ -564,7 +566,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
   test('it should not include new records when serializing a hasMany relationship', function (assert) {
     this.owner.register(
       'serializer:user',
-      DS.JSONAPISerializer.extend({
+      JSONAPISerializer.extend({
         attrs: {
           handles: { serialize: true },
         },
@@ -623,7 +625,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
   test('it should not include any records when serializing a hasMany relationship if they are all new', function (assert) {
     this.owner.register(
       'serializer:user',
-      DS.JSONAPISerializer.extend({
+      JSONAPISerializer.extend({
         attrs: {
           handles: { serialize: true },
         },
@@ -667,7 +669,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
   test('it should include an empty list when serializing an empty hasMany relationship', function (assert) {
     this.owner.register(
       'serializer:user',
-      DS.JSONAPISerializer.extend({
+      JSONAPISerializer.extend({
         attrs: {
           handles: { serialize: true },
         },
@@ -725,13 +727,13 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', functi
 
   testInDebug('Asserts when combined with EmbeddedRecordsMixin', function (assert) {
     assert.expectAssertion(function () {
-      DS.JSONAPISerializer.extend(DS.EmbeddedRecordsMixin).create();
+      JSONAPISerializer.extend(DS.EmbeddedRecordsMixin).create();
     }, /You've used the EmbeddedRecordsMixin in/);
   });
 
   testInDebug('Allows EmbeddedRecordsMixin if isEmbeddedRecordsMixinCompatible is true', function (assert) {
     assert.expectNoAssertion(function () {
-      DS.JSONAPISerializer.extend(DS.EmbeddedRecordsMixin, {
+      JSONAPISerializer.extend(DS.EmbeddedRecordsMixin, {
         isEmbeddedRecordsMixinCompatible: true,
       }).create();
     });
diff --git a/packages/-ember-data/tests/integration/snapshot-test.js b/packages/-ember-data/tests/integration/snapshot-test.js
index de352ae531b..76c1b8a704f 100644
--- a/packages/-ember-data/tests/integration/snapshot-test.js
+++ b/packages/-ember-data/tests/integration/snapshot-test.js
@@ -38,7 +38,7 @@ module('integration/snapshot - Snapshot', function (hooks) {
     owner.register('model:post', Post);
     owner.register('model:comment', Comment);
     owner.register('adapter:application', JSONAPIAdapter.extend());
-    owner.register('serializer:application', JSONAPISerializer.extend());
+    owner.register('serializer:application', class extends JSONAPISerializer {});
     store = owner.lookup('service:store');
   });
 
diff --git a/packages/-ember-data/tests/integration/store-test.js b/packages/-ember-data/tests/integration/store-test.js
index c3e85526c7d..3164d2e2dc5 100644
--- a/packages/-ember-data/tests/integration/store-test.js
+++ b/packages/-ember-data/tests/integration/store-test.js
@@ -66,7 +66,7 @@ module('integration/store - destroy', function (hooks) {
     this.owner.register('model:person', Person);
 
     this.owner.register('adapter:application', DS.Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test("destroying record during find doesn't cause unexpected error (find resolves)", async function (assert) {
@@ -429,7 +429,7 @@ module('integration/store - findRecord', function (hooks) {
     });
 
     this.owner.register('adapter:application', testAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let car = await store.findRecord('car', '1');
 
@@ -477,7 +477,7 @@ module('integration/store - findRecord', function (hooks) {
     }
 
     this.owner.register('adapter:application', TestAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     let firstPromise, secondPromise;
 
     firstPromise = store.findRecord('car', '1', { reload: true });
@@ -521,7 +521,7 @@ module('integration/store - findRecord', function (hooks) {
     });
 
     this.owner.register('adapter:application', testAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     let firstPromise, secondPromise;
 
     run(() => {
@@ -1169,7 +1169,7 @@ module('integration/store - deleteRecord', function (hooks) {
     });
 
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register('model:car', Car);
 
     let store = this.owner.lookup('service:store');
@@ -1210,7 +1210,7 @@ module('integration/store - queryRecord', function (hooks) {
   hooks.beforeEach(function () {
     this.owner.register('model:car', Car);
     this.owner.register('adapter:application', DS.Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   testInDebug(
diff --git a/packages/-ember-data/tests/integration/store/query-record-test.js b/packages/-ember-data/tests/integration/store/query-record-test.js
index 278484a63fc..e0941093df0 100644
--- a/packages/-ember-data/tests/integration/store/query-record-test.js
+++ b/packages/-ember-data/tests/integration/store/query-record-test.js
@@ -18,7 +18,7 @@ module('integration/store/query-record - Query one record with a query hash', fu
     });
 
     this.owner.register('model:person', Person);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   testInDebug('It raises an assertion when no type is passed', function (assert) {
@@ -55,7 +55,7 @@ module('integration/store/query-record - Query one record with a query hash', fu
       })
     );
 
-    this.owner.register('serializer:application', DS.JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     run(function () {
       store.queryRecord('person', { related: 'posts' });
@@ -86,16 +86,16 @@ module('integration/store/query-record - Query one record with a query hash', fu
 
     this.owner.register(
       'serializer:person',
-      DS.JSONAPISerializer.extend({
+      class extends JSONAPISerializer {
         normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) {
           assert.strictEqual(
             payload.data.id,
             '1',
             'the normalizeQueryRecordResponse method was called with the right payload'
           );
-          return this._super(...arguments);
-        },
-      })
+          return super.normalizeQueryRecordResponse(...arguments);
+        }
+      }
     );
 
     this.owner.register(
diff --git a/packages/-ember-data/tests/integration/store/query-test.js b/packages/-ember-data/tests/integration/store/query-test.js
index b9510ff2898..6a4d004c7a6 100644
--- a/packages/-ember-data/tests/integration/store/query-test.js
+++ b/packages/-ember-data/tests/integration/store/query-test.js
@@ -16,7 +16,7 @@ module('integration/store/query', function (hooks) {
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', DS.Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('meta is proxied correctly on the PromiseArray', function (assert) {
diff --git a/packages/-ember-data/tests/unit/adapter-errors-test.js b/packages/-ember-data/tests/unit/adapter-errors-test.js
index 3a6651767ea..e5632b97b79 100644
--- a/packages/-ember-data/tests/unit/adapter-errors-test.js
+++ b/packages/-ember-data/tests/unit/adapter-errors-test.js
@@ -4,6 +4,7 @@ import { module, test } from 'qunit';
 
 import DS from 'ember-data';
 
+import { DEPRECATE_HELPERS } from '@ember-data/private-build-infra/deprecations';
 import testInDebug from '@ember-data/unpublished-test-infra/test-support/test-in-debug';
 
 module('unit/adapter-errors - DS.AdapterError', function () {
@@ -105,75 +106,82 @@ module('unit/adapter-errors - DS.AdapterError', function () {
     assert.strictEqual(error.message, 'custom error!');
   });
 
-  const errorsHash = {
-    name: ['is invalid', 'must be a string'],
-    age: ['must be a number'],
-  };
-
-  const errorsArray = [
-    {
-      title: 'Invalid Attribute',
-      detail: 'is invalid',
-      source: { pointer: '/data/attributes/name' },
-    },
-    {
-      title: 'Invalid Attribute',
-      detail: 'must be a string',
-      source: { pointer: '/data/attributes/name' },
-    },
-    {
-      title: 'Invalid Attribute',
-      detail: 'must be a number',
-      source: { pointer: '/data/attributes/age' },
-    },
-  ];
-
-  const errorsPrimaryHash = {
-    base: ['is invalid', 'error message'],
-  };
-
-  const errorsPrimaryArray = [
-    {
-      title: 'Invalid Document',
-      detail: 'is invalid',
-      source: { pointer: '/data' },
-    },
-    {
-      title: 'Invalid Document',
-      detail: 'error message',
-      source: { pointer: '/data' },
-    },
-  ];
-
-  test('errorsHashToArray', function (assert) {
-    let result = DS.errorsHashToArray(errorsHash);
-    assert.deepEqual(result, errorsArray);
-  });
+  if (DEPRECATE_HELPERS) {
+    const errorsHash = {
+      name: ['is invalid', 'must be a string'],
+      age: ['must be a number'],
+    };
 
-  test('errorsHashToArray for primary data object', function (assert) {
-    let result = DS.errorsHashToArray(errorsPrimaryHash);
-    assert.deepEqual(result, errorsPrimaryArray);
-  });
+    const errorsArray = [
+      {
+        title: 'Invalid Attribute',
+        detail: 'is invalid',
+        source: { pointer: '/data/attributes/name' },
+      },
+      {
+        title: 'Invalid Attribute',
+        detail: 'must be a string',
+        source: { pointer: '/data/attributes/name' },
+      },
+      {
+        title: 'Invalid Attribute',
+        detail: 'must be a number',
+        source: { pointer: '/data/attributes/age' },
+      },
+    ];
 
-  test('errorsArrayToHash', function (assert) {
-    let result = DS.errorsArrayToHash(errorsArray);
-    assert.deepEqual(result, errorsHash);
-  });
+    const errorsPrimaryHash = {
+      base: ['is invalid', 'error message'],
+    };
 
-  test('errorsArrayToHash without trailing slash', function (assert) {
-    let result = DS.errorsArrayToHash([
+    const errorsPrimaryArray = [
+      {
+        title: 'Invalid Document',
+        detail: 'is invalid',
+        source: { pointer: '/data' },
+      },
       {
+        title: 'Invalid Document',
         detail: 'error message',
-        source: { pointer: 'data/attributes/name' },
+        source: { pointer: '/data' },
       },
-    ]);
-    assert.deepEqual(result, { name: ['error message'] });
-  });
-
-  test('errorsArrayToHash for primary data object', function (assert) {
-    let result = DS.errorsArrayToHash(errorsPrimaryArray);
-    assert.deepEqual(result, errorsPrimaryHash);
-  });
+    ];
+
+    test('errorsHashToArray', function (assert) {
+      let result = DS.errorsHashToArray(errorsHash);
+      assert.deepEqual(result, errorsArray);
+      assert.expectDeprecation({ id: 'ember-data:deprecate-errors-hash-to-array-helper', count: 1 });
+    });
+
+    test('errorsHashToArray for primary data object', function (assert) {
+      let result = DS.errorsHashToArray(errorsPrimaryHash);
+      assert.deepEqual(result, errorsPrimaryArray);
+      assert.expectDeprecation({ id: 'ember-data:deprecate-errors-hash-to-array-helper', count: 1 });
+    });
+
+    test('errorsArrayToHash', function (assert) {
+      let result = DS.errorsArrayToHash(errorsArray);
+      assert.deepEqual(result, errorsHash);
+      assert.expectDeprecation({ id: 'ember-data:deprecate-errors-array-to-hash-helper', count: 1 });
+    });
+
+    test('errorsArrayToHash without trailing slash', function (assert) {
+      let result = DS.errorsArrayToHash([
+        {
+          detail: 'error message',
+          source: { pointer: 'data/attributes/name' },
+        },
+      ]);
+      assert.deepEqual(result, { name: ['error message'] });
+      assert.expectDeprecation({ id: 'ember-data:deprecate-errors-array-to-hash-helper', count: 1 });
+    });
+
+    test('errorsArrayToHash for primary data object', function (assert) {
+      let result = DS.errorsArrayToHash(errorsPrimaryArray);
+      assert.deepEqual(result, errorsPrimaryHash);
+      assert.expectDeprecation({ id: 'ember-data:deprecate-errors-array-to-hash-helper', count: 1 });
+    });
+  }
 
   testInDebug('DS.InvalidError will normalize errors hash will assert', function (assert) {
     assert.expectAssertion(function () {
diff --git a/packages/-ember-data/tests/unit/adapters/json-api-adapter/ajax-options-test.js b/packages/-ember-data/tests/unit/adapters/json-api-adapter/ajax-options-test.js
index ec911d00038..d0a99b1f497 100644
--- a/packages/-ember-data/tests/unit/adapters/json-api-adapter/ajax-options-test.js
+++ b/packages/-ember-data/tests/unit/adapters/json-api-adapter/ajax-options-test.js
@@ -15,7 +15,7 @@ module('unit/adapters/json-api-adapter/ajax-options - building requests', functi
         useFetch = true;
       }
     );
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('ajaxOptions() adds Accept when no other headers exist', function (assert) {
diff --git a/packages/-ember-data/tests/unit/model-test.js b/packages/-ember-data/tests/unit/model-test.js
index d25a8625f29..7ca91c61356 100644
--- a/packages/-ember-data/tests/unit/model-test.js
+++ b/packages/-ember-data/tests/unit/model-test.js
@@ -39,7 +39,7 @@ module('unit/model - Model', function (hooks) {
       })
     );
     owner.register('serializer:-default', JSONAPISerializer);
-    owner.register('serializer:application', JSONAPISerializer.extend());
+    owner.register('serializer:application', class extends JSONAPISerializer {});
 
     store = owner.lookup('service:store');
     adapter = store.adapterFor('application');
diff --git a/packages/-ember-data/tests/unit/model/init-properties-test.js b/packages/-ember-data/tests/unit/model/init-properties-test.js
index e2690af897f..bac459f4fa9 100644
--- a/packages/-ember-data/tests/unit/model/init-properties-test.js
+++ b/packages/-ember-data/tests/unit/model/init-properties-test.js
@@ -44,7 +44,7 @@ function setupModels(owner, testState) {
   owner.register('model:author', Author);
 
   owner.register('adapter:application', JSONAPIAdapter.extend());
-  owner.register('serializer:application', JSONAPISerializer.extend());
+  owner.register('serializer:application', class extends JSONAPISerializer {});
 
   let store = owner.lookup('service:store');
   let adapter = store.adapterFor('application');
@@ -275,7 +275,7 @@ module('unit/model - init properties', function (hooks) {
 
     this.owner.register('model:post', Post);
     this.owner.register('adapter:application', JSONAPIAdapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
diff --git a/packages/-ember-data/tests/unit/model/merge-test.js b/packages/-ember-data/tests/unit/model/merge-test.js
index d945cb2dd83..20146bef561 100644
--- a/packages/-ember-data/tests/unit/model/merge-test.js
+++ b/packages/-ember-data/tests/unit/model/merge-test.js
@@ -20,7 +20,7 @@ module('unit/model/merge - Merging', function (hooks) {
     });
 
     this.owner.register('model:person', Person);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     this.store = this.owner.lookup('service:store');
   });
diff --git a/packages/-ember-data/tests/unit/model/relationships/belongs-to-test.js b/packages/-ember-data/tests/unit/model/relationships/belongs-to-test.js
index aba7b289622..1098eb46c29 100644
--- a/packages/-ember-data/tests/unit/model/relationships/belongs-to-test.js
+++ b/packages/-ember-data/tests/unit/model/relationships/belongs-to-test.js
@@ -17,7 +17,7 @@ module('unit/model/relationships - belongsTo', function (hooks) {
 
   hooks.beforeEach(function () {
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('belongsTo lazily loads relationships as needed', function (assert) {
diff --git a/packages/-ember-data/tests/unit/model/relationships/has-many-test.js b/packages/-ember-data/tests/unit/model/relationships/has-many-test.js
index bc5b2e4bdd1..0b78b88cee5 100644
--- a/packages/-ember-data/tests/unit/model/relationships/has-many-test.js
+++ b/packages/-ember-data/tests/unit/model/relationships/has-many-test.js
@@ -19,7 +19,7 @@ module('unit/model/relationships - hasMany', function (hooks) {
 
   hooks.beforeEach(function () {
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('hasMany handles pre-loaded relationships', function (assert) {
diff --git a/packages/-ember-data/tests/unit/model/rollback-attributes-test.js b/packages/-ember-data/tests/unit/model/rollback-attributes-test.js
index fbfdbde8d32..0ceaf1e48a5 100644
--- a/packages/-ember-data/tests/unit/model/rollback-attributes-test.js
+++ b/packages/-ember-data/tests/unit/model/rollback-attributes-test.js
@@ -33,7 +33,7 @@ module('unit/model/rollbackAttributes - model.rollbackAttributes()', function (h
 
       this.owner.register('model:person', Person);
       this.owner.register('adapter:application', Adapter.extend());
-      this.owner.register('serializer:application', JSONAPISerializer.extend());
+      this.owner.register('serializer:application', class extends JSONAPISerializer {});
     });
 
     test('changes to attributes can be rolled back', function (assert) {
diff --git a/packages/-ember-data/tests/unit/promise-proxies-test.js b/packages/-ember-data/tests/unit/promise-proxies-test.js
index 4da1180613e..374a028a218 100644
--- a/packages/-ember-data/tests/unit/promise-proxies-test.js
+++ b/packages/-ember-data/tests/unit/promise-proxies-test.js
@@ -151,7 +151,7 @@ module('unit/PromiseBelongsTo', function (hooks) {
     owner.register('model:parent', Parent);
     owner.register('model:child', Child);
     owner.register('adapter:child', ChildAdapter);
-    owner.register('serializer:application', JSONAPISerializer.extend());
+    owner.register('serializer:application', class extends JSONAPISerializer {});
     const store = owner.lookup('service:store');
     const meta = {
       example: 'example meta',
diff --git a/packages/-ember-data/tests/unit/store/adapter-interop-test.js b/packages/-ember-data/tests/unit/store/adapter-interop-test.js
index fa616fbe99b..3289c9b869c 100644
--- a/packages/-ember-data/tests/unit/store/adapter-interop-test.js
+++ b/packages/-ember-data/tests/unit/store/adapter-interop-test.js
@@ -42,7 +42,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
     });
 
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register('model:test', Model.extend());
 
     return run(() => currentStore.findRecord('test', 1));
@@ -69,7 +69,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
     });
 
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register('model:test', Model.extend());
 
     let store = this.owner.lookup('service:store');
@@ -131,7 +131,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
     });
 
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register('model:test', Model.extend());
 
     let store = this.owner.lookup('service:store');
@@ -153,7 +153,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
     });
 
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register('model:test', Model.extend({ name: attr() }));
 
     let store = this.owner.lookup('service:store');
@@ -176,7 +176,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
     });
 
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register('model:test', Model.extend({ name: attr() }));
 
     let store = this.owner.lookup('service:store');
@@ -226,7 +226,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -278,7 +278,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -323,7 +323,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
     });
 
     this.owner.register('model:person', Person);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -457,7 +457,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:test', TestModel);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -481,7 +481,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -517,7 +517,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -550,7 +550,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -587,7 +587,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -611,7 +611,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -637,7 +637,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -668,7 +668,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -709,7 +709,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:test', Model.extend());
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -752,7 +752,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
     });
 
     this.owner.register('model:test', Model.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register('adapter:application', ApplicationAdapter);
 
     let store = this.owner.lookup('service:store');
@@ -805,7 +805,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
     });
 
     this.owner.register('model:test', Model.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
     this.owner.register('adapter:application', ApplicationAdapter);
 
     let store = this.owner.lookup('service:store');
@@ -845,7 +845,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
       this.owner.register('model:test', Model.extend());
       this.owner.register('adapter:application', ApplicationAdapter);
-      this.owner.register('serializer:application', JSONAPISerializer.extend());
+      this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
       let store = this.owner.lookup('service:store');
 
@@ -875,7 +875,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:test', Model.extend());
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -921,7 +921,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Model.extend());
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -946,7 +946,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Model.extend());
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -978,7 +978,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Model.extend({ name: attr() }));
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -1018,7 +1018,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -1052,7 +1052,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Model.extend());
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -1086,7 +1086,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Model.extend({ name: attr() }));
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -1126,7 +1126,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Model.extend());
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -1153,7 +1153,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -1186,7 +1186,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -1217,7 +1217,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Model.extend());
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
@@ -1252,7 +1252,7 @@ module('unit/store/adapter-interop - Store working with a Adapter', function (ho
 
     this.owner.register('model:person', Person);
     this.owner.register('adapter:application', ApplicationAdapter);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     let store = this.owner.lookup('service:store');
 
diff --git a/packages/-ember-data/tests/unit/store/finders-test.js b/packages/-ember-data/tests/unit/store/finders-test.js
index 5d98aa7e601..d7e5551e595 100644
--- a/packages/-ember-data/tests/unit/store/finders-test.js
+++ b/packages/-ember-data/tests/unit/store/finders-test.js
@@ -26,7 +26,7 @@ module('unit/store/finders', function (hooks) {
   hooks.beforeEach(function () {
     this.owner.register('model:person', Person);
     this.owner.register('model:dog', Dog);
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
 
     this.store = this.owner.lookup('service:store');
     this.adapter = this.store.adapterFor('application');
diff --git a/packages/-ember-data/tests/unit/store/push-test.js b/packages/-ember-data/tests/unit/store/push-test.js
index bac04624a86..910f3e15111 100644
--- a/packages/-ember-data/tests/unit/store/push-test.js
+++ b/packages/-ember-data/tests/unit/store/push-test.js
@@ -30,7 +30,7 @@ module('unit/store/push - Store#push', function (hooks) {
     }
     this.owner.register('model:phone-number', PhoneNumber);
 
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('Changed attributes are reset when matching data is pushed', function (assert) {
@@ -862,7 +862,7 @@ module('unit/store/push - Store#pushPayload', function (hooks) {
         @hasMany('person', { async: false, inverse: 'friends' }) friends; // many to many
       }
       this.owner.register('model:person', Person);
-      this.owner.register('serializer:application', JSONAPISerializer.extend());
+      this.owner.register('serializer:application', class extends JSONAPISerializer {});
       // one person with two friends
       // if we push a change to a friend, the
       // person's friends should be in the same order
@@ -950,7 +950,7 @@ module('unit/store/push - Store#push with JSON-API', function (hooks) {
     this.owner.register('model:car', Car);
 
     this.owner.register('adapter:application', Adapter.extend());
-    this.owner.register('serializer:application', JSONAPISerializer.extend());
+    this.owner.register('serializer:application', class extends JSONAPISerializer {});
   });
 
   test('Should support pushing multiple models into the store', function (assert) {
diff --git a/packages/adapter/addon/error.js b/packages/adapter/addon/error.js
index 4b01b544140..9dedfe0a64f 100644
--- a/packages/adapter/addon/error.js
+++ b/packages/adapter/addon/error.js
@@ -1,9 +1,11 @@
 /**
   @module @ember-data/adapter/error
  */
-import { assert } from '@ember/debug';
+import { assert, deprecate } from '@ember/debug';
 import EmberError from '@ember/error';
 
+import { DEPRECATE_HELPERS } from '@ember-data/private-build-infra/deprecations';
+
 /**
   A `AdapterError` is used by an adapter to signal that an error occurred
   during a request to an external API. It indicates a generic error, and
@@ -179,6 +181,7 @@ AdapterError.extend = extendFn(AdapterError);
   @public
   @extends AdapterError
 */
+// TODO @deprecate extractError documentation
 export const InvalidError = extend(AdapterError, 'The adapter rejected the commit because it was invalid');
 InvalidError.prototype.code = 'InvalidError';
 
@@ -343,4 +346,164 @@ ConflictError.prototype.code = 'ConflictError';
 export const ServerError = extend(AdapterError, 'The adapter operation failed due to a server error');
 ServerError.prototype.code = 'ServerError';
 
-export { errorsHashToArray, errorsArrayToHash } from '@ember-data/store/-private';
+function makeArray(value) {
+  return Array.isArray(value) ? value : [value];
+}
+
+const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/;
+const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/;
+const PRIMARY_ATTRIBUTE_KEY = 'base';
+/**
+  Convert an hash of errors into an array with errors in JSON-API format.
+   ```javascript
+  import DS from 'ember-data';
+
+   const { errorsHashToArray } = DS;
+
+   let errors = {
+    base: 'Invalid attributes on saving this record',
+    name: 'Must be present',
+    age: ['Must be present', 'Must be a number']
+  };
+   let errorsArray = errorsHashToArray(errors);
+  // [
+  //   {
+  //     title: "Invalid Document",
+  //     detail: "Invalid attributes on saving this record",
+  //     source: { pointer: "/data" }
+  //   },
+  //   {
+  //     title: "Invalid Attribute",
+  //     detail: "Must be present",
+  //     source: { pointer: "/data/attributes/name" }
+  //   },
+  //   {
+  //     title: "Invalid Attribute",
+  //     detail: "Must be present",
+  //     source: { pointer: "/data/attributes/age" }
+  //   },
+  //   {
+  //     title: "Invalid Attribute",
+  //     detail: "Must be a number",
+  //     source: { pointer: "/data/attributes/age" }
+  //   }
+  // ]
+  ```
+  @method errorsHashToArray
+  @for @ember-data/adapter/error
+  @static
+  @deprecated
+  @public
+  @param {Object} errors hash with errors as properties
+  @return {Array} array of errors in JSON-API format
+*/
+export function errorsHashToArray(errors) {
+  if (DEPRECATE_HELPERS) {
+    deprecate(`errorsHashToArray helper has been deprecated.`, false, {
+      id: 'ember-data:deprecate-errors-hash-to-array-helper',
+      for: 'ember-data',
+      until: '5.0',
+      since: { available: '4.8', enabled: '4.8' },
+    });
+    let out = [];
+
+    if (errors) {
+      Object.keys(errors).forEach((key) => {
+        let messages = makeArray(errors[key]);
+        for (let i = 0; i < messages.length; i++) {
+          let title = 'Invalid Attribute';
+          let pointer = `/data/attributes/${key}`;
+          if (key === PRIMARY_ATTRIBUTE_KEY) {
+            title = 'Invalid Document';
+            pointer = `/data`;
+          }
+          out.push({
+            title: title,
+            detail: messages[i],
+            source: {
+              pointer: pointer,
+            },
+          });
+        }
+      });
+    }
+
+    return out;
+  }
+  assert(`errorsHashToArray helper has been removed`);
+}
+
+/**
+  Convert an array of errors in JSON-API format into an object.
+
+  ```javascript
+  import DS from 'ember-data';
+
+  const { errorsArrayToHash } = DS;
+
+  let errorsArray = [
+    {
+      title: 'Invalid Attribute',
+      detail: 'Must be present',
+      source: { pointer: '/data/attributes/name' }
+    },
+    {
+      title: 'Invalid Attribute',
+      detail: 'Must be present',
+      source: { pointer: '/data/attributes/age' }
+    },
+    {
+      title: 'Invalid Attribute',
+      detail: 'Must be a number',
+      source: { pointer: '/data/attributes/age' }
+    }
+  ];
+
+  let errors = errorsArrayToHash(errorsArray);
+  // {
+  //   "name": ["Must be present"],
+  //   "age":  ["Must be present", "must be a number"]
+  // }
+  ```
+
+  @method errorsArrayToHash
+  @static
+  @for @ember-data/adapter/error
+  @deprecated
+  @public
+  @param {Array} errors array of errors in JSON-API format
+  @return {Object}
+*/
+export function errorsArrayToHash(errors) {
+  if (DEPRECATE_HELPERS) {
+    deprecate(`errorsArrayToHash helper has been deprecated.`, false, {
+      id: 'ember-data:deprecate-errors-array-to-hash-helper',
+      for: 'ember-data',
+      until: '5.0',
+      since: { available: '4.8', enabled: '4.8' },
+    });
+    let out = {};
+
+    if (errors) {
+      errors.forEach((error) => {
+        if (error.source && error.source.pointer) {
+          let key = error.source.pointer.match(SOURCE_POINTER_REGEXP);
+
+          if (key) {
+            key = key[2];
+          } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) {
+            key = PRIMARY_ATTRIBUTE_KEY;
+          }
+
+          if (key) {
+            out[key] = out[key] || [];
+            out[key].push(error.detail || error.title);
+          }
+        }
+      });
+    }
+
+    return out;
+  }
+  assert(`errorsArrayToHash helper has been removed`);
+}
diff --git a/packages/model/addon/-private/model.js b/packages/model/addon/-private/model.js
index 6cc4f1ffe91..1f96be63551 100644
--- a/packages/model/addon/-private/model.js
+++ b/packages/model/addon/-private/model.js
@@ -22,14 +22,7 @@ import {
   DEPRECATE_SAVE_PROMISE_ACCESS,
 } from '@ember-data/private-build-infra/deprecations';
 import { recordIdentifierFor, storeFor } from '@ember-data/store';
-import {
-  coerceId,
-  deprecatedPromiseObject,
-  errorsArrayToHash,
-  InternalModel,
-  recordDataFor,
-  WeakCache,
-} from '@ember-data/store/-private';
+import { coerceId, deprecatedPromiseObject, InternalModel, WeakCache } from '@ember-data/store/-private';
 
 import Errors from './errors';
 import { LegacySupport } from './legacy-relationships-support';
@@ -569,22 +562,7 @@ class Model extends EmberObject {
   @computeOnce
   get errors() {
     let errors = Errors.create({ __record: this });
-    // TODO we should unify how errors gets populated
-    // with the code managing the update. Probably a
-    // lazy flush similar to retrieveLatest in ManyArray
-    let recordData = recordDataFor(this);
-    let jsonApiErrors;
-    if (recordData.getErrors) {
-      jsonApiErrors = recordData.getErrors();
-      if (jsonApiErrors) {
-        let errorsHash = errorsArrayToHash(jsonApiErrors);
-        let errorKeys = Object.keys(errorsHash);
-
-        for (let i = 0; i < errorKeys.length; i++) {
-          errors.add(errorKeys[i], errorsHash[errorKeys[i]]);
-        }
-      }
-    }
+    this.currentState.updateInvalidErrors(errors);
     return errors;
   }
 
diff --git a/packages/model/addon/-private/record-state.ts b/packages/model/addon/-private/record-state.ts
index 37434f920f5..2c520c0caa6 100644
--- a/packages/model/addon/-private/record-state.ts
+++ b/packages/model/addon/-private/record-state.ts
@@ -5,7 +5,7 @@ import { cached, tracked } from '@glimmer/tracking';
 
 import type Store from '@ember-data/store';
 import { storeFor } from '@ember-data/store';
-import { errorsArrayToHash, recordIdentifierFor } from '@ember-data/store/-private';
+import { recordIdentifierFor } from '@ember-data/store/-private';
 import type { NotificationType } from '@ember-data/store/-private/record-notification-manager';
 import type RequestCache from '@ember-data/store/-private/request-cache';
 import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
@@ -13,6 +13,9 @@ import type { RecordData } from '@ember-data/types/q/record-data';
 
 type Model = InstanceType<typeof import('./model')>;
 
+const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/;
+const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/;
+const PRIMARY_ATTRIBUTE_KEY = 'base';
 function isInvalidError(error) {
   return error && error.isAdapterError === true && error.code === 'InvalidError';
 }
@@ -176,7 +179,6 @@ export default class RecordState {
             break;
           case 'rejected':
             this.isSaving = false;
-
             this._lastError = req;
             if (!(req.response && isInvalidError(req.response.data))) {
               this._errorRequests.push(req);
@@ -246,11 +248,7 @@ export default class RecordState {
           this.notify('isDeleted');
           break;
         case 'errors':
-          // we only hit this if a foreign RecordData notifies
-          // errors changed. Our own implementation does not
-          // take this path currently, but we should probably
-          // fix that.
-          this.updateInvalidErrors();
+          this.updateInvalidErrors(this.record.errors);
           this.notify('isValid');
           break;
       }
@@ -261,16 +259,33 @@ export default class RecordState {
     getTag(this, key).notify();
   }
 
-  updateInvalidErrors() {
-    let jsonApiErrors = this.recordData.getErrors!(this.identifier);
+  updateInvalidErrors(errors) {
+    assert(
+      `Expected the RecordData instance for ${this.identifier}  to implement getErrors(identifier)`,
+      typeof this.recordData.getErrors === 'function'
+    );
+    let jsonApiErrors = this.recordData.getErrors(this.identifier);
 
-    const { errors } = this.record;
     errors.clear();
-    let newErrors = errorsArrayToHash(jsonApiErrors);
-    let errorKeys = Object.keys(newErrors);
 
-    for (let i = 0; i < errorKeys.length; i++) {
-      errors.add(errorKeys[i], newErrors[errorKeys[i]]);
+    for (let i = 0; i < jsonApiErrors.length; i++) {
+      let error = jsonApiErrors[i];
+
+      if (error.source && error.source.pointer) {
+        let keyMatch = error.source.pointer.match(SOURCE_POINTER_REGEXP);
+        let key: string | undefined;
+
+        if (keyMatch) {
+          key = keyMatch[2];
+        } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) {
+          key = PRIMARY_ATTRIBUTE_KEY;
+        }
+
+        if (key) {
+          let errMsg = error.detail || error.title;
+          errors.add(key, errMsg);
+        }
+      }
     }
   }
 
diff --git a/packages/model/addon/-private/relationship-meta.ts b/packages/model/addon/-private/relationship-meta.ts
index 5c7ee813e5b..e38b25f6d33 100644
--- a/packages/model/addon/-private/relationship-meta.ts
+++ b/packages/model/addon/-private/relationship-meta.ts
@@ -1,9 +1,9 @@
+import { dasherize } from '@ember/string';
 import { DEBUG } from '@glimmer/env';
 
 import { singularize } from 'ember-inflector';
 
 import type Store from '@ember-data/store';
-import { normalizeModelName } from '@ember-data/store/-private';
 import type { RelationshipSchema } from '@ember-data/types/q/record-data-schemas';
 
 /**
@@ -11,7 +11,7 @@ import type { RelationshipSchema } from '@ember-data/types/q/record-data-schemas
 */
 
 function typeForRelationshipMeta(meta) {
-  let modelName = normalizeModelName(meta.type || meta.key);
+  let modelName = dasherize(meta.type || meta.key);
 
   if (meta.kind === 'hasMany') {
     modelName = singularize(modelName);
diff --git a/packages/model/index.js b/packages/model/index.js
index f39981b5f9a..55f8503c966 100644
--- a/packages/model/index.js
+++ b/packages/model/index.js
@@ -17,6 +17,7 @@ module.exports = Object.assign({}, addonBaseConfig, {
       '@ember-data/store/-private',
       '@ember-data/store/-debug',
       '@embroider/macros',
+      '@ember/string',
       '@embroider/macros/es-compat',
 
       '@ember/application',
diff --git a/packages/private-build-infra/addon/current-deprecations.ts b/packages/private-build-infra/addon/current-deprecations.ts
index 058890fb8d5..f8b014e3a38 100644
--- a/packages/private-build-infra/addon/current-deprecations.ts
+++ b/packages/private-build-infra/addon/current-deprecations.ts
@@ -50,4 +50,5 @@ export default {
   DEPRECATE_MODEL_REOPEN: '4.8',
   DEPRECATE_EARLY_STATIC: '4.8',
   DEPRECATE_CLASSIC: '4.9',
+  DEPRECATE_HELPERS: '4.8',
 };
diff --git a/packages/private-build-infra/addon/deprecations.ts b/packages/private-build-infra/addon/deprecations.ts
index 4dc46181e40..2a21099af5c 100644
--- a/packages/private-build-infra/addon/deprecations.ts
+++ b/packages/private-build-infra/addon/deprecations.ts
@@ -19,3 +19,4 @@ export const DEPRECATE_JSON_API_FALLBACK = deprecationState('DEPRECATE_JSON_API_
 export const DEPRECATE_MODEL_REOPEN = deprecationState('DEPRECATE_MODEL_REOPEN');
 export const DEPRECATE_EARLY_STATIC = deprecationState('DEPRECATE_EARLY_STATIC');
 export const DEPRECATE_CLASSIC = deprecationState('DEPRECATE_CLASSIC');
+export const DEPRECATE_HELPERS = deprecationState('DEPRECATE_HELPERS');
diff --git a/packages/serializer/addon/json-api.js b/packages/serializer/addon/json-api.js
index 79939dbd14f..f503c839b6c 100644
--- a/packages/serializer/addon/json-api.js
+++ b/packages/serializer/addon/json-api.js
@@ -9,7 +9,6 @@ import { DEBUG } from '@glimmer/env';
 import { pluralize, singularize } from 'ember-inflector';
 
 import JSONSerializer from '@ember-data/serializer/json';
-import { normalizeModelName } from '@ember-data/store';
 
 /**
   Ember Data 2.0 Serializer:
@@ -361,7 +360,7 @@ const JSONAPISerializer = JSONSerializer.extend({
     @return {String} the model's modelName
   */
   modelNameFromPayloadKey(key) {
-    return singularize(normalizeModelName(key));
+    return singularize(dasherize(key));
   },
 
   /**
diff --git a/packages/serializer/addon/json.js b/packages/serializer/addon/json.js
index fc75eabef7c..aa63ab6c14d 100644
--- a/packages/serializer/addon/json.js
+++ b/packages/serializer/addon/json.js
@@ -4,14 +4,18 @@
 import { getOwner } from '@ember/application';
 import { assert, warn } from '@ember/debug';
 import { get } from '@ember/object';
+import { dasherize } from '@ember/string';
 import { isNone, typeOf } from '@ember/utils';
 
 import Serializer from '@ember-data/serializer';
-import { normalizeModelName } from '@ember-data/store';
-import { coerceId, errorsArrayToHash } from '@ember-data/store/-private';
+import { coerceId } from '@ember-data/store/-private';
 
 import { modelHasAttributeOrRelationshipNamedType } from './-private';
 
+const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/;
+const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/;
+const PRIMARY_ATTRIBUTE_KEY = 'base';
+
 /**
   Ember Data 2.0 Serializer:
 
@@ -795,7 +799,7 @@ const JSONSerializer = Serializer.extend({
     @return {String} the model's modelName
   */
   modelNameFromPayloadKey(key) {
-    return normalizeModelName(key);
+    return dasherize(key);
   },
 
   /**
@@ -1467,25 +1471,48 @@ const JSONSerializer = Serializer.extend({
   */
   extractErrors(store, typeClass, payload, id) {
     if (payload && typeof payload === 'object' && payload.errors) {
-      payload = errorsArrayToHash(payload.errors);
+      // the default assumption is that errors is already in JSON:API format
+      const extracted = {};
+
+      payload.errors.forEach((error) => {
+        if (error.source && error.source.pointer) {
+          let key = error.source.pointer.match(SOURCE_POINTER_REGEXP);
 
-      this.normalizeUsingDeclaredMapping(typeClass, payload);
+          if (key) {
+            key = key[2];
+          } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) {
+            key = PRIMARY_ATTRIBUTE_KEY;
+          }
 
+          if (key) {
+            extracted[key] = extracted[key] || [];
+            extracted[key].push(error.detail || error.title);
+          }
+        }
+      });
+
+      // if the user has an attrs hash, convert keys using it
+      this.normalizeUsingDeclaredMapping(typeClass, extracted);
+
+      // for each attr and relationship, make sure that we use
+      // the normalized key
       typeClass.eachAttribute((name) => {
         let key = this.keyForAttribute(name, 'deserialize');
-        if (key !== name && payload[key] !== undefined) {
-          payload[name] = payload[key];
-          delete payload[key];
+        if (key !== name && extracted[key] !== undefined) {
+          extracted[name] = extracted[key];
+          delete extracted[key];
         }
       });
 
       typeClass.eachRelationship((name) => {
         let key = this.keyForRelationship(name, 'deserialize');
-        if (key !== name && payload[key] !== undefined) {
-          payload[name] = payload[key];
-          delete payload[key];
+        if (key !== name && extracted[key] !== undefined) {
+          extracted[name] = extracted[key];
+          delete extracted[key];
         }
       });
+
+      return extracted;
     }
 
     return payload;
diff --git a/packages/serializer/addon/rest.js b/packages/serializer/addon/rest.js
index 079841bdc98..e107f9fd7cb 100644
--- a/packages/serializer/addon/rest.js
+++ b/packages/serializer/addon/rest.js
@@ -1,20 +1,22 @@
 /**
  * @module @ember-data/serializer/rest
  */
-import { makeArray } from '@ember/array';
 import { assert, warn } from '@ember/debug';
-import { camelize } from '@ember/string';
+import { camelize, dasherize } from '@ember/string';
 import { isNone, typeOf } from '@ember/utils';
 import { DEBUG } from '@glimmer/env';
 
 import { singularize } from 'ember-inflector';
 
 import JSONSerializer from '@ember-data/serializer/json';
-import { normalizeModelName } from '@ember-data/store';
 import { coerceId } from '@ember-data/store/-private';
 
 import { modelHasAttributeOrRelationshipNamedType } from './-private';
 
+function makeArray(value) {
+  return Array.isArray(value) ? value : [value];
+}
+
 /**
   Normally, applications will use the `RESTSerializer` by implementing
   the `normalize` method.
@@ -350,7 +352,7 @@ const RESTSerializer = JSONSerializer.extend({
   },
 
   isPrimaryType(store, modelName, primaryModelClass) {
-    return normalizeModelName(modelName) === primaryModelClass.modelName;
+    return dasherize(modelName) === primaryModelClass.modelName;
   },
 
   /**
@@ -473,7 +475,7 @@ const RESTSerializer = JSONSerializer.extend({
     @return {String} the model's modelName
   */
   modelNameFromPayloadKey(key) {
-    return singularize(normalizeModelName(key));
+    return singularize(dasherize(key));
   },
 
   // SERIALIZE
diff --git a/packages/store/addon/-private/core-store.ts b/packages/store/addon/-private/core-store.ts
index 73263af5a99..9efb8d2f35b 100644
--- a/packages/store/addon/-private/core-store.ts
+++ b/packages/store/addon/-private/core-store.ts
@@ -1788,7 +1788,10 @@ class Store extends Service {
       if (DEBUG) {
         assertDestroyingStore(this, 'recordWasInvalid');
       }
-      internalModel.adapterDidInvalidate(parsedErrors, error);
+      error = error || new Error(`unknown invalid error`);
+      error = typeof error === 'string' ? new Error(error) : error;
+      error._parsedErrors = parsedErrors;
+      internalModel.adapterDidInvalidate(error);
     }
     assert(`store.recordWasInvalid has been removed`);
   }
@@ -2182,7 +2185,8 @@ class Store extends Service {
 
           //We first make sure the primary data has been updated
           //TODO try to move notification to the user to the end of the runloop
-          internalModel.adapterDidCommit(data);
+          internalModel._recordData.didCommit(data);
+          this.recordArrayManager.recordDidChange(internalModel.identifier);
 
           if (payload && payload.included) {
             this._push({ data: null, included: payload.included });
@@ -2191,12 +2195,14 @@ class Store extends Service {
         return record;
       },
       (e) => {
-        if (typeof e === 'string') {
-          throw e;
+        let err = e;
+        if (!e) {
+          err = new Error(`Unknown Error Occurred During Request`);
+        } else if (typeof e === 'string') {
+          err = new Error(e);
         }
-        const { error, parsedErrors } = e;
-        internalModel.adapterDidInvalidate(parsedErrors, error);
-        throw error;
+        internalModel.adapterDidInvalidate(err);
+        throw err;
       }
     );
   }
diff --git a/packages/store/addon/-private/errors-utils.js b/packages/store/addon/-private/errors-utils.js
deleted file mode 100644
index 3e805fb71cc..00000000000
--- a/packages/store/addon/-private/errors-utils.js
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
-  @module @ember-data/adapter/error
-*/
-
-const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/;
-const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/;
-const PRIMARY_ATTRIBUTE_KEY = 'base';
-
-function makeArray(value) {
-  return Array.isArray(value) ? value : [value];
-}
-
-/**
-  Convert an hash of errors into an array with errors in JSON-API format.
-   ```javascript
-  import DS from 'ember-data';
-
-   const { errorsHashToArray } = DS;
-
-   let errors = {
-    base: 'Invalid attributes on saving this record',
-    name: 'Must be present',
-    age: ['Must be present', 'Must be a number']
-  };
-   let errorsArray = errorsHashToArray(errors);
-  // [
-  //   {
-  //     title: "Invalid Document",
-  //     detail: "Invalid attributes on saving this record",
-  //     source: { pointer: "/data" }
-  //   },
-  //   {
-  //     title: "Invalid Attribute",
-  //     detail: "Must be present",
-  //     source: { pointer: "/data/attributes/name" }
-  //   },
-  //   {
-  //     title: "Invalid Attribute",
-  //     detail: "Must be present",
-  //     source: { pointer: "/data/attributes/age" }
-  //   },
-  //   {
-  //     title: "Invalid Attribute",
-  //     detail: "Must be a number",
-  //     source: { pointer: "/data/attributes/age" }
-  //   }
-  // ]
-  ```
-  @method errorsHashToArray
-  @for @ember-data/adapter/error
-  @static
-  @public
-  @param {Object} errors hash with errors as properties
-  @return {Array} array of errors in JSON-API format
-*/
-export function errorsHashToArray(errors) {
-  let out = [];
-
-  if (errors) {
-    Object.keys(errors).forEach((key) => {
-      let messages = makeArray(errors[key]);
-      for (let i = 0; i < messages.length; i++) {
-        let title = 'Invalid Attribute';
-        let pointer = `/data/attributes/${key}`;
-        if (key === PRIMARY_ATTRIBUTE_KEY) {
-          title = 'Invalid Document';
-          pointer = `/data`;
-        }
-        out.push({
-          title: title,
-          detail: messages[i],
-          source: {
-            pointer: pointer,
-          },
-        });
-      }
-    });
-  }
-
-  return out;
-}
-
-/**
-  Convert an array of errors in JSON-API format into an object.
-
-  ```javascript
-  import DS from 'ember-data';
-
-  const { errorsArrayToHash } = DS;
-
-  let errorsArray = [
-    {
-      title: 'Invalid Attribute',
-      detail: 'Must be present',
-      source: { pointer: '/data/attributes/name' }
-    },
-    {
-      title: 'Invalid Attribute',
-      detail: 'Must be present',
-      source: { pointer: '/data/attributes/age' }
-    },
-    {
-      title: 'Invalid Attribute',
-      detail: 'Must be a number',
-      source: { pointer: '/data/attributes/age' }
-    }
-  ];
-
-  let errors = errorsArrayToHash(errorsArray);
-  // {
-  //   "name": ["Must be present"],
-  //   "age":  ["Must be present", "must be a number"]
-  // }
-  ```
-
-  @method errorsArrayToHash
-  @static
-  @for @ember-data/adapter/error
-  @public
-  @param {Array} errors array of errors in JSON-API format
-  @return {Object}
-*/
-export function errorsArrayToHash(errors) {
-  let out = {};
-
-  if (errors) {
-    errors.forEach((error) => {
-      if (error.source && error.source.pointer) {
-        let key = error.source.pointer.match(SOURCE_POINTER_REGEXP);
-
-        if (key) {
-          key = key[2];
-        } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) {
-          key = PRIMARY_ATTRIBUTE_KEY;
-        }
-
-        if (key) {
-          out[key] = out[key] || [];
-          out[key].push(error.detail || error.title);
-        }
-      }
-    });
-  }
-
-  return out;
-}
diff --git a/packages/store/addon/-private/fetch-manager.ts b/packages/store/addon/-private/fetch-manager.ts
index cc4e42764a2..e2695ac00ff 100644
--- a/packages/store/addon/-private/fetch-manager.ts
+++ b/packages/store/addon/-private/fetch-manager.ts
@@ -22,7 +22,6 @@ import type { Dict } from '@ember-data/types/q/utils';
 import coerceId from './coerce-id';
 import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './common';
 import type Store from './core-store';
-import { errorsArrayToHash } from './errors-utils';
 import ShimModelClass from './model/shim-model-class';
 import RequestCache from './request-cache';
 import { normalizeResponseHelper } from './serializer-response';
@@ -170,24 +169,7 @@ export default class FetchManager {
         if (adapterPayload) {
           return normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation);
         }
-      },
-      function (error) {
-        if (error && error.isAdapterError === true && error.code === 'InvalidError') {
-          let parsedErrors = error.errors;
-
-          // TODO deprecate extractErrors being called and/or make it part of the public interface
-          if (serializer && typeof serializer.extractErrors === 'function') {
-            parsedErrors = serializer.extractErrors(store, modelClass, error, snapshot.id);
-          } else {
-            parsedErrors = errorsArrayToHash(error.errors);
-          }
-
-          throw { error, parsedErrors };
-        } else {
-          throw { error };
-        }
-      },
-      label
+      }
     );
     resolver.resolve(promise);
   }
@@ -326,38 +308,32 @@ export default class FetchManager {
       }),
       this._store,
       label
-    ).then(
-      (adapterPayload) => {
-        assert(
-          `You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`,
-          !!payloadIsNotBlank(adapterPayload)
-        );
-        let serializer = this._store.serializerFor(modelName);
-        let payload = normalizeResponseHelper(serializer, this._store, klass, adapterPayload, id, 'findRecord');
-        assert(
-          `Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`,
-          !Array.isArray(payload.data)
-        );
-        assert(
-          `The 'findRecord' request for ${modelName}:${id} resolved indicating success but contained no primary data. To indicate a 404 not found you should either reject the promise returned by the adapter's findRecord method or throw a NotFoundError.`,
-          'data' in payload && payload.data !== null && typeof payload.data === 'object'
-        );
+    ).then((adapterPayload) => {
+      assert(
+        `You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`,
+        !!payloadIsNotBlank(adapterPayload)
+      );
+      let serializer = this._store.serializerFor(modelName);
+      let payload = normalizeResponseHelper(serializer, this._store, klass, adapterPayload, id, 'findRecord');
+      assert(
+        `Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`,
+        !Array.isArray(payload.data)
+      );
+      assert(
+        `The 'findRecord' request for ${modelName}:${id} resolved indicating success but contained no primary data. To indicate a 404 not found you should either reject the promise returned by the adapter's findRecord method or throw a NotFoundError.`,
+        'data' in payload && payload.data !== null && typeof payload.data === 'object'
+      );
 
-        warn(
-          `You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead.`,
-          coerceId(payload.data.id) === coerceId(id),
-          {
-            id: 'ds.store.findRecord.id-mismatch',
-          }
-        );
+      warn(
+        `You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead.`,
+        coerceId(payload.data.id) === coerceId(id),
+        {
+          id: 'ds.store.findRecord.id-mismatch',
+        }
+      );
 
-        return payload;
-      },
-      (error) => {
-        throw error;
-      },
-      `DS: Extract payload of '${modelName}'`
-    );
+      return payload;
+    });
 
     fetchItem.resolver.resolve(promise);
   }
diff --git a/packages/store/addon/-private/index.ts b/packages/store/addon/-private/index.ts
index 6233a059c0f..c012b97c5e0 100644
--- a/packages/store/addon/-private/index.ts
+++ b/packages/store/addon/-private/index.ts
@@ -2,6 +2,12 @@
   @module @ember-data/store
 */
 
+import { assert, deprecate } from '@ember/debug';
+
+import { DEPRECATE_HELPERS } from '@ember-data/private-build-infra/deprecations';
+
+import _normalize from './normalize-model-name';
+
 export { default as Store, storeFor } from './core-store';
 
 export { recordIdentifierFor } from './internal-model-factory';
@@ -14,10 +20,24 @@ export {
   setIdentifierResetMethod,
 } from './identifier-cache';
 
-export { default as normalizeModelName } from './normalize-model-name';
-export { default as coerceId } from './coerce-id';
+export function normalizeModelName(modelName: string) {
+  if (DEPRECATE_HELPERS) {
+    deprecate(
+      `the helper function normalizeModelName is deprecated. You should use model names that are already normalized, or use string helpers of your own. This function is primarily an alias for dasherize from @ember/string.`,
+      false,
+      {
+        id: 'ember-data:deprecate-normalize-modelname-helper',
+        for: 'ember-data',
+        until: '5.0',
+        since: { available: '4.8', enabled: '4.8' },
+      }
+    );
+    return _normalize(modelName);
+  }
+  assert(`normalizeModelName support has been removed`);
+}
 
-export { errorsHashToArray, errorsArrayToHash } from './errors-utils';
+export { default as coerceId } from './coerce-id';
 
 // `ember-data-model-fragments` relies on `InternalModel`
 export { default as InternalModel } from './model/internal-model';
diff --git a/packages/store/addon/-private/model/internal-model.ts b/packages/store/addon/-private/model/internal-model.ts
index 27c1b413ac6..9ea227c42b1 100644
--- a/packages/store/addon/-private/model/internal-model.ts
+++ b/packages/store/addon/-private/model/internal-model.ts
@@ -5,13 +5,14 @@ import { DEBUG } from '@glimmer/env';
 import { HAS_MODEL_PACKAGE } from '@ember-data/private-build-infra';
 import type { DSModel } from '@ember-data/types/q/ds-model';
 import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
+import type { MinimumSerializerInterface } from '@ember-data/types/q/minimum-serializer-interface';
 import type { ChangedAttributesHash, RecordData } from '@ember-data/types/q/record-data';
 import type { JsonApiResource, JsonApiValidationError } from '@ember-data/types/q/record-data-json-api';
 import type { RecordInstance } from '@ember-data/types/q/record-instance';
 
 import type Store from '../core-store';
-import { errorsHashToArray } from '../errors-utils';
 import { internalModelFactoryFor } from '../internal-model-factory';
+import type ShimModelClass from './shim-model-class';
 
 /**
   @module @ember-data/store
@@ -27,6 +28,11 @@ function isDSModel(record: RecordInstance | null): record is DSModel {
   );
 }
 
+type AdapterErrors = Error & { errors?: unknown[]; isAdapterError?: true; code?: string };
+type SerializerWithParseErrors = MinimumSerializerInterface & {
+  extractErrors?(store: Store, modelClass: ShimModelClass, error: AdapterErrors, recordId: string | null): any;
+};
+
 export default class InternalModel {
   declare _id: string | null;
   declare modelName: string;
@@ -91,7 +97,10 @@ export default class InternalModel {
       let newIdentifier = { type: this.identifier.type, lid: this.identifier.lid, id: value };
       // TODO potentially this needs to handle merged result
       this.store.identifierCache.updateRecordIdentifier(this.identifier, newIdentifier);
-      this.notifyPropertyChange('id');
+      if (this.hasRecord) {
+        // TODO this should likely *mostly* be the a different bucket
+        this.store._notificationManager.notify(this.identifier, 'property', 'id');
+      }
     }
   }
 
@@ -392,16 +401,6 @@ export default class InternalModel {
     }
   }
 
-  notifyPropertyChange(key: string) {
-    if (this.hasRecord) {
-      // TODO this should likely *mostly* be the `attributes` bucket
-      // but it seems for local mutations we rely on computed updating
-      // iteself when set. As we design our own thing we may need to change
-      // that.
-      this.store._notificationManager.notify(this.identifier, 'property', key);
-    }
-  }
-
   notifyStateChange(key?: string) {
     if (this.hasRecord) {
       this.store._notificationManager.notify(this.identifier, 'state');
@@ -533,52 +532,26 @@ export default class InternalModel {
     this._isUpdatingId = false;
   }
 
-  didError() {}
-
-  /*
-    If the adapter did not return a hash in response to a commit,
-    merge the changed attributes and relationships into the existing
-    saved data.
-  */
-  adapterDidCommit(data) {
-    this._recordData.didCommit(data);
-    this.store.recordArrayManager.recordDidChange(this.identifier);
-  }
-
-  hasErrors(): boolean {
-    // TODO add assertion forcing consuming RecordData's to implement getErrors
-    if (this._recordData.getErrors) {
-      return this._recordData.getErrors(this.identifier).length > 0;
-    } else {
-      let record = this.store._instanceCache.peek({ identifier: this.identifier, bucket: 'record' });
-      // we can't have errors if we never tried loading
-      if (!record) {
-        return false;
+  // FOR USE DURING COMMIT PROCESS
+  adapterDidInvalidate(error: Error & { errors?: JsonApiValidationError[]; isAdapterError?: true; code?: string }) {
+    if (error && error.isAdapterError === true && error.code === 'InvalidError') {
+      let serializer = this.store.serializerFor(this.modelName) as SerializerWithParseErrors;
+
+      // TODO @deprecate extractErrors being called
+      // TODO remove extractErrors from the default serializers.
+      if (serializer && typeof serializer.extractErrors === 'function') {
+        let errorsHash = serializer.extractErrors(this.store, this.store.modelFor(this.modelName), error, this.id);
+        error.errors = errorsHashToArray(errorsHash);
       }
-      let errors = (record as DSModel).errors;
-      return errors.length > 0;
     }
-  }
 
-  // FOR USE DURING COMMIT PROCESS
-  adapterDidInvalidate(parsedErrors, error?) {
-    // TODO @runspired this should be handled by RecordState
-    // and errors should be dirtied but lazily fetch if at
-    // all possible. We should only notify errors here.
-    let attribute;
-    if (error && parsedErrors) {
-      // TODO add assertion forcing consuming RecordData's to implement getErrors
-      if (!this._recordData.getErrors) {
-        let record = this.store._instanceCache.getRecord(this.identifier) as DSModel;
-        let errors = record.errors;
-        for (attribute in parsedErrors) {
-          if (Object.prototype.hasOwnProperty.call(parsedErrors, attribute)) {
-            errors.add(attribute, parsedErrors[attribute]);
-          }
-        }
-      }
+    if (error.errors) {
+      assert(
+        `Expected the RecordData implementation for ${this.identifier} to have a getErrors(identifier) method for retreiving errors.`,
+        typeof this._recordData.getErrors === 'function'
+      );
 
-      let jsonApiErrors: JsonApiValidationError[] = errorsHashToArray(parsedErrors);
+      let jsonApiErrors: JsonApiValidationError[] = error.errors;
       if (jsonApiErrors.length === 0) {
         jsonApiErrors = [{ title: 'Invalid Error', detail: '', source: { pointer: '/data' } }];
       }
@@ -588,15 +561,40 @@ export default class InternalModel {
     }
   }
 
-  notifyErrorsChange() {
-    this.store._notificationManager.notify(this.identifier, 'errors');
+  toString() {
+    return `<${this.modelName}:${this.id}>`;
   }
+}
 
-  adapterDidError() {
-    this._recordData.commitWasRejected();
-  }
+function makeArray(value) {
+  return Array.isArray(value) ? value : [value];
+}
 
-  toString() {
-    return `<${this.modelName}:${this.id}>`;
+const PRIMARY_ATTRIBUTE_KEY = 'base';
+
+function errorsHashToArray(errors): JsonApiValidationError[] {
+  const out: JsonApiValidationError[] = [];
+
+  if (errors) {
+    Object.keys(errors).forEach((key) => {
+      let messages = makeArray(errors[key]);
+      for (let i = 0; i < messages.length; i++) {
+        let title = 'Invalid Attribute';
+        let pointer = `/data/attributes/${key}`;
+        if (key === PRIMARY_ATTRIBUTE_KEY) {
+          title = 'Invalid Document';
+          pointer = `/data`;
+        }
+        out.push({
+          title: title,
+          detail: messages[i],
+          source: {
+            pointer: pointer,
+          },
+        });
+      }
+    });
   }
+
+  return out;
 }
diff --git a/packages/store/addon/-private/normalize-model-name.ts b/packages/store/addon/-private/normalize-model-name.ts
index 67fb2569ea0..7fd5caacef5 100644
--- a/packages/store/addon/-private/normalize-model-name.ts
+++ b/packages/store/addon/-private/normalize-model-name.ts
@@ -4,9 +4,6 @@ import { dasherize } from '@ember/string';
   @module @ember-data/store
 */
 
-// All modelNames are dasherized internally. Changing this function may
-// require changes to other normalization hooks (such as typeForRoot).
-
 /**
  This method normalizes a modelName into the format Ember Data uses
  internally by dasherizing it.
@@ -14,6 +11,7 @@ import { dasherize } from '@ember/string';
   @method normalizeModelName
   @static
   @public
+  @deprecated
   @for @ember-data/store
   @param {String} modelName
   @return {String} normalizedModelName
diff --git a/packages/store/addon/-private/record-data-store-wrapper.ts b/packages/store/addon/-private/record-data-store-wrapper.ts
index 8efca4589c3..9f0be766b84 100644
--- a/packages/store/addon/-private/record-data-store-wrapper.ts
+++ b/packages/store/addon/-private/record-data-store-wrapper.ts
@@ -75,11 +75,7 @@ export default class RecordDataStoreWrapper implements StoreWrapper {
     const resource = constructResource(type, id, lid);
     const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
 
-    let internalModel = internalModelFactoryFor(this._store).peek(identifier);
-
-    if (internalModel) {
-      internalModel.notifyErrorsChange();
-    }
+    this._store._notificationManager.notify(identifier, 'errors');
   }
 
   _flushNotifications(): void {
diff --git a/packages/store/addon/-private/request-cache.ts b/packages/store/addon/-private/request-cache.ts
index 30b55854b07..a63c0eead34 100644
--- a/packages/store/addon/-private/request-cache.ts
+++ b/packages/store/addon/-private/request-cache.ts
@@ -62,7 +62,7 @@ export default class RequestCache {
             state: 'rejected',
             request: queryRequest,
             type,
-            response: { data: error && error.error },
+            response: { data: error },
           } as InternalRequest;
           finalizedRequest[Touching] = request[Touching];
           this._addDone(finalizedRequest);