diff --git a/dimod/binary_quadratic_model.py b/dimod/binary_quadratic_model.py
index 970163c3..3cbe679d 100644
--- a/dimod/binary_quadratic_model.py
+++ b/dimod/binary_quadratic_model.py
@@ -46,12 +46,12 @@ of a problem.
 """
 from __future__ import absolute_import, division
 
-from collections import Sized, Container, Iterable
+from collections import Sized, Container, Iterable, OrderedDict
 from numbers import Number
 
 import numpy as np
 
-from six import itervalues, iteritems, iterkeys, viewkeys
+from six import itervalues, iteritems, iterkeys
 
 from dimod.decorators import vartype_argument
 from dimod.response import SampleView
@@ -263,11 +263,6 @@ class BinaryQuadraticModel(Sized, Container, Iterable):
     def __iter__(self):
         return self.adj.__iter__()
 
-    @property
-    def variables(self):
-        """Returns BQM's variables as a dictionary view object."""
-        return viewkeys(self.linear)
-
 ##################################################################################################
 # vartype properties
 ##################################################################################################
@@ -2200,3 +2195,37 @@ class BinaryQuadraticModel(Sized, Container, Iterable):
             bqm.add_interaction(u, v, 0.0)
 
         return bqm
+
+
+class OrderedBinaryQuadraticModel(BinaryQuadraticModel):
+    """Consistently ordered variant of :class:`BinaryQuadraticModel`.
+
+    Uses :class:`collections.OrderedDict` to store the linear and quadratic biases. Note that
+    :attr:`~.BinaryQuadraticModel.adj` remains unordered.
+
+    Variables are ordered by insertion. This is well defined if adding the variable/interactions
+    singly, but not when constructed from unordered mappings like dicts.
+
+    Examples:
+
+        >>> bqm = dimod.OrderedBinaryQuadraticModel.empty(dimod.SPIN)
+        >>> bqm.add_variable('a', .5)
+        >>> bqm.add_interaction('a', 'b', 1.5)
+        >>> bqm.linear
+        OrderedDict([('a', 0.5), ('b', 0.0)])
+        >>> bqm.quadratic
+        OrderedDict([(('a', 'b'), 1.5)])
+
+    """
+    @vartype_argument('vartype')
+    def __init__(self, linear, quadratic, offset, vartype, **kwargs):
+        self.linear = OrderedDict()
+        self.quadratic = OrderedDict()
+        self.adj = {}
+        self.offset = offset  # we are agnostic to type, though generally should behave like a number
+        self.vartype = vartype
+        self.info = kwargs  # any additional kwargs are kept as info (metadata)
+
+        # add linear, quadratic
+        self.add_variables_from(linear)
+        self.add_interactions_from(quadratic)
diff --git a/docs/reference/binary_quadratic_model.rst b/docs/reference/binary_quadratic_model.rst
index a2d55fea..ac3d3ce4 100644
--- a/docs/reference/binary_quadratic_model.rst
+++ b/docs/reference/binary_quadratic_model.rst
@@ -108,3 +108,9 @@ Converting to other types
    BinaryQuadraticModel.to_numpy_vectors
    BinaryQuadraticModel.to_qubo
    BinaryQuadraticModel.to_pandas_dataframe
+
+
+OrderedBinaryQuadraticModel
+===========================
+
+.. autoclass:: OrderedBinaryQuadraticModel

Allow user-specified mapping type for `BinaryQuadraticModel`s
```
bqm = dimod.BinaryQuadraticModel(linear, quadratic, offset, vartype, mapping_type=OrderedDict)
```
This would affect `.linear` and `.quadratic`, possibly `.adj` as well.
diff --git a/tests/test_binary_quadratic_model.py b/tests/test_binary_quadratic_model.py
index de1211b3..958e1904 100644
--- a/tests/test_binary_quadratic_model.py
+++ b/tests/test_binary_quadratic_model.py
@@ -20,6 +20,8 @@ import itertools
 import tempfile
 import shutil
 import json
+import collections
+
 from os import path
 
 import jsonschema
@@ -135,7 +137,6 @@ class TestBinaryQuadraticModel(unittest.TestCase):
 
         self.assertEqual(dimod.BinaryQuadraticModel(linear, quadratic, offset, 'BINARY').vartype, dimod.BINARY)
 
-
     def test_construction_quadratic(self):
         linear = {v: v * .01 for v in range(10)}
         quadratic = {(u, v): u * v * .01 for u, v in itertools.combinations(linear, 2)}
@@ -226,18 +227,6 @@ class TestBinaryQuadraticModel(unittest.TestCase):
 
         self.assertEqual(set(bqm), {'a', 'b'})
 
-    def test_variables(self):
-        bqm = dimod.BinaryQuadraticModel.empty(dimod.BINARY)
-
-        self.assertEqual(set(bqm.variables), set())
-
-        bqm.add_interaction('a', 'b', -1)
-
-        self.assertEqual(set(bqm.variables), {'a', 'b'})
-        self.assertIn('a', bqm.variables)
-        self.assertEqual(bqm.variables & {'b'}, {'b'})
-        self.assertEqual(bqm.variables | {'c'}, {'a', 'b', 'c'})
-
     def test_add_variable(self):
         bqm = dimod.BinaryQuadraticModel({}, {('a', 'b'): -1}, 0.0, dimod.SPIN)
         bqm.add_variable('a', .5)
@@ -1887,3 +1876,18 @@ class TestConvert(unittest.TestCase):
         self.assertIn('tag', new_bqm.info)
         self.assertEqual(new_bqm.info['tag'], 5)
         self.assertIn(('a', "complex key"), new_bqm.linear)
+
+
+class TestOrderedBQM(unittest.TestCase):
+    def test_construction(self):
+        bqm = dimod.OrderedBinaryQuadraticModel.empty(dimod.SPIN)
+        bqm.add_variable('a', .5)
+        bqm.add_interaction('c', 'a', 1.5)
+        bqm.add_interaction('a', 'c', -1.)
+        bqm.add_interaction('a', 'b', -1.)
+        bqm.add_variables_from([('b', 1.0), ('c', 1.0)])
+        bqm.add_interaction('e', 'd', 0.0)
+
+        self.assertEqual(bqm.linear, collections.OrderedDict([('a', .5), ('c', 1.), ('b', 1.), ('e', 0.), ('d', 0.)]))
+        self.assertEqual(bqm.quadratic,
+                         collections.OrderedDict([(('c', 'a'), .5), (('a', 'b'), -1.), (('e', 'd'), 0.0)]))

pip install -e .[all]
parse_log_pytest
requirements.txt
pytest
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
charset-normalizer==2.0.12
codecov==2.1.13
coverage==6.2
decorator==5.1.1
-e git+https://github.com/dwavesystems/dimod.git@8ebfffa42319aa4850cfc5a1c99a8711eac44722#egg=dimod
idna==3.10
importlib-metadata==4.8.3
iniconfig==1.1.1
jsonschema==2.6.0
mock==2.0.0
networkx==2.0
numpy==1.14.5
packaging==21.3
pandas==0.22.0
pbr==6.1.1
pluggy==1.0.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
python-dateutil==2.9.0.post0
pytz==2025.2
requests==2.27.1
six==1.11.0
tomli==1.2.3
typing_extensions==4.1.1
urllib3==1.26.20
zipp==3.6.0

name: dimod
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - charset-normalizer==2.0.12
      - codecov==2.1.13
      - coverage==6.2
      - decorator==5.1.1
      - idna==3.10
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - jsonschema==2.6.0
      - mock==2.0.0
      - networkx==2.0
      - numpy==1.14.5
      - packaging==21.3
      - pandas==0.22.0
      - pbr==6.1.1
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - requests==2.27.1
      - six==1.11.0
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - zipp==3.6.0
prefix: /opt/conda/envs/dimod

tests/test_binary_quadratic_model.py::TestOrderedBQM::test_construction
tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test__contains__ tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test__eq__ tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test__iter__ tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test__len__ tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test__repr__ tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_add_interaction tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_add_interaction_counterpart tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_add_interactions_from tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_add_offset tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_add_variable tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_add_variable_counterpart tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_add_variables_from tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_binary_property tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_binary_property_relabel tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_change_vartype tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_constract_variables tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_construction tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_construction_quadratic tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_construction_vartype tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_copy tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_fix_variable tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_flip_variable tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_partial_relabel_copy tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_partial_relabel_inplace tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_relabel_typical tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_relabel_typical_copy tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_relabel_typical_inplace tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_relabel_with_identity tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_relabel_with_overlap tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_remove_interaction tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_remove_interactions_from tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_remove_offset tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_remove_variable tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_remove_variables_from tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_scale tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_spin_property tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_spin_property_relabel tests/test_binary_quadratic_model.py::TestBinaryQuadraticModel::test_update tests/test_binary_quadratic_model.py::TestConvert::test_coo_functional_file_BINARY tests/test_binary_quadratic_model.py::TestConvert::test_coo_functional_file_SPIN tests/test_binary_quadratic_model.py::TestConvert::test_coo_functional_file_empty_BINARY tests/test_binary_quadratic_model.py::TestConvert::test_coo_functional_file_empty_SPIN tests/test_binary_quadratic_model.py::TestConvert::test_coo_functional_string_BINARY tests/test_binary_quadratic_model.py::TestConvert::test_coo_functional_string_SPIN tests/test_binary_quadratic_model.py::TestConvert::test_coo_functional_string_empty_BINARY tests/test_binary_quadratic_model.py::TestConvert::test_coo_functional_string_empty_SPIN tests/test_binary_quadratic_model.py::TestConvert::test_coo_functional_two_digit_integers_string tests/test_binary_quadratic_model.py::TestConvert::test_empty tests/test_binary_quadratic_model.py::TestConvert::test_from_coo_file tests/test_binary_quadratic_model.py::TestConvert::test_from_coo_string tests/test_binary_quadratic_model.py::TestConvert::test_from_ising tests/test_binary_quadratic_model.py::TestConvert::test_from_numpy_matrix tests/test_binary_quadratic_model.py::TestConvert::test_from_numpy_vectors tests/test_binary_quadratic_model.py::TestConvert::test_from_numpy_vectors_labels tests/test_binary_quadratic_model.py::TestConvert::test_from_qubo tests/test_binary_quadratic_model.py::TestConvert::test_functional_to_and_from_json tests/test_binary_quadratic_model.py::TestConvert::test_functional_to_and_from_json_empty tests/test_binary_quadratic_model.py::TestConvert::test_functional_to_and_from_json_with_info tests/test_binary_quadratic_model.py::TestConvert::test_info tests/test_binary_quadratic_model.py::TestConvert::test_to_coo_string_empty_BINARY tests/test_binary_quadratic_model.py::TestConvert::test_to_coo_string_empty_SPIN tests/test_binary_quadratic_model.py::TestConvert::test_to_coo_string_typical_BINARY tests/test_binary_quadratic_model.py::TestConvert::test_to_coo_string_typical_SPIN tests/test_binary_quadratic_model.py::TestConvert::test_to_ising_binary_to_ising tests/test_binary_quadratic_model.py::TestConvert::test_to_ising_spin_to_ising tests/test_binary_quadratic_model.py::TestConvert::test_to_json_file tests/test_binary_quadratic_model.py::TestConvert::test_to_json_file_empty tests/test_binary_quadratic_model.py::TestConvert::test_to_json_string tests/test_binary_quadratic_model.py::TestConvert::test_to_json_string_empty tests/test_binary_quadratic_model.py::TestConvert::test_to_networkx_graph tests/test_binary_quadratic_model.py::TestConvert::test_to_numpy_matrix tests/test_binary_quadratic_model.py::TestConvert::test_to_numpy_vectors tests/test_binary_quadratic_model.py::TestConvert::test_to_numpy_vectors_labels_sorted tests/test_binary_quadratic_model.py::TestConvert::test_to_numpy_vectors_sorted tests/test_binary_quadratic_model.py::TestConvert::test_to_pandas_dataframe tests/test_binary_quadratic_model.py::TestConvert::test_to_qubo_binary_to_qubo tests/test_binary_quadratic_model.py::TestConvert::test_to_qubo_spin_to_qubo
dimod/binary_quadratic_model.py docs/reference/binary_quadratic_model.rst
dimod/binary_quadratic_model.py docs/reference/binary_quadratic_model.rst