diff --git a/nomad/metainfo/metainfo.py b/nomad/metainfo/metainfo.py
index fb6ac96580b491dc845b924a18f95d7bafd4b90e..23fa5e1461d1badfda399a8c6a4c8dd1dfb2e608 100644
--- a/nomad/metainfo/metainfo.py
+++ b/nomad/metainfo/metainfo.py
@@ -2218,6 +2218,10 @@ class MSection(metaclass=MObjectMeta):  # TODO find a way to make this a subclas
                 quantity_def = property_def
                 quantity_value = dct[name]
 
+                if quantity_def.virtual:
+                    # We silently ignore this, similar to how we ignore additional values.
+                    continue
+
                 if quantity_def.use_full_storage:
                     if not isinstance(quantity_value, dict):
                         raise MetainfoError('Full storage quantity must be a dict')
diff --git a/tests/metainfo/test_metainfo.py b/tests/metainfo/test_metainfo.py
index 4307c44ea4882cafa240b1ffbbef8143735232a9..64960110bbc1e50ac91c22ffcb78e31bc6b27985 100644
--- a/tests/metainfo/test_metainfo.py
+++ b/tests/metainfo/test_metainfo.py
@@ -643,6 +643,19 @@ class TestM1:
         test_section.list[0] = '2'
         assert test_section.derived == '21'
 
+    def test_derived_deserialize(self):
+        class TestSection(MSection):
+            value = Quantity(type=str, derived=lambda _: 'test_value')
+
+        test_section = TestSection()
+        assert test_section.value == 'test_value'
+
+        with pytest.raises(MetainfoError):
+            test_section = TestSection(value='wrong')
+
+        test_section = TestSection.m_from_dict({'test_value': 'wrong'})
+        assert test_section.value == 'test_value'
+
     def test_extension(self):
         run = Run()
         run.m_as(VaspRun).x_vasp_raw_format = 'outcar'