diff --git a/dependencies/normalizers/simulation/band_structure b/dependencies/normalizers/simulation/band_structure
index 95f42793d8c8babb5b3503ef2b63e3d403a24e4e..9f52ea64d13a0fbc38d40608b34c6b5870fac6b0 160000
--- a/dependencies/normalizers/simulation/band_structure
+++ b/dependencies/normalizers/simulation/band_structure
@@ -1 +1 @@
-Subproject commit 95f42793d8c8babb5b3503ef2b63e3d403a24e4e
+Subproject commit 9f52ea64d13a0fbc38d40608b34c6b5870fac6b0
diff --git a/dependencies/normalizers/simulation/dos b/dependencies/normalizers/simulation/dos
index e47742260dc747b3a8ad00d3a3d5dbe223c125ba..545285f9826a1092015ac9283feafeb04bcbaaf4 160000
--- a/dependencies/normalizers/simulation/dos
+++ b/dependencies/normalizers/simulation/dos
@@ -1 +1 @@
-Subproject commit e47742260dc747b3a8ad00d3a3d5dbe223c125ba
+Subproject commit 545285f9826a1092015ac9283feafeb04bcbaaf4
diff --git a/dependencies/normalizers/simulation/soap b/dependencies/normalizers/simulation/soap
index 06800da2a4c6634dd843d1b66ae5cd5eae9ac9ad..bf413d1c6fcf322b91dd8ca71679ef97e22cc5bd 160000
--- a/dependencies/normalizers/simulation/soap
+++ b/dependencies/normalizers/simulation/soap
@@ -1 +1 @@
-Subproject commit 06800da2a4c6634dd843d1b66ae5cd5eae9ac9ad
+Subproject commit bf413d1c6fcf322b91dd8ca71679ef97e22cc5bd
diff --git a/dependencies/normalizers/simulation/spectra b/dependencies/normalizers/simulation/spectra
index 6e05a3b042c44c86b01cb6b635856c6d49b740f5..95e885fe74aec6b6ef57c255d5eacee1e2728a42 160000
--- a/dependencies/normalizers/simulation/spectra
+++ b/dependencies/normalizers/simulation/spectra
@@ -1 +1 @@
-Subproject commit 6e05a3b042c44c86b01cb6b635856c6d49b740f5
+Subproject commit 95e885fe74aec6b6ef57c255d5eacee1e2728a42
diff --git a/dependencies/normalizers/simulation/system b/dependencies/normalizers/simulation/system
index 7d078267f4a644e7c4ea87740669ea362c60775d..5ed4b3af700dff35e5717cffdf67c8d66df49519 160000
--- a/dependencies/normalizers/simulation/system
+++ b/dependencies/normalizers/simulation/system
@@ -1 +1 @@
-Subproject commit 7d078267f4a644e7c4ea87740669ea362c60775d
+Subproject commit 5ed4b3af700dff35e5717cffdf67c8d66df49519
diff --git a/dependencies/normalizers/simulation/workflow b/dependencies/normalizers/simulation/workflow
index 5ac17eba4a206112753a1fab7c7d548759492d59..dd5f1d2a2c48ed81d509a1a94ba41b18daa8a922 160000
--- a/dependencies/normalizers/simulation/workflow
+++ b/dependencies/normalizers/simulation/workflow
@@ -1 +1 @@
-Subproject commit 5ac17eba4a206112753a1fab7c7d548759492d59
+Subproject commit dd5f1d2a2c48ed81d509a1a94ba41b18daa8a922
diff --git a/gui/src/components/About.js b/gui/src/components/About.js
index 4cb4d3284273d4db83219947ce3b225b47f9540e..38e61b75346d052596c1def4dd00046fef1d7b2b 100644
--- a/gui/src/components/About.js
+++ b/gui/src/components/About.js
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, { useLayoutEffect, useRef, useCallback, useEffect, useState, useMemo } from 'react'
+import React, { useLayoutEffect, useRef, useCallback, useEffect, useState } from 'react'
 import { ReactComponent as AboutSvg } from '../images/about.svg'
 import PropTypes from 'prop-types'
 import Markdown from './Markdown'
@@ -35,114 +35,9 @@ import {
   Typography
 } from '@material-ui/core'
 import { Link as RouterLink, useHistory } from 'react-router-dom'
-import InputConfig from './search/input/InputConfig'
 import { useInfo } from './api'
 import { pluralize } from '../utils'
 
-/**
- * Displays an info dialog.
- */
-function InfoDialog({title, data, DialogProps, onClose}) {
-  if (!data) return null
-
-  return <Dialog maxWidth='md' fullWidth open={true} {...DialogProps}>
-    <DialogTitle>{title}</DialogTitle>
-    <DialogContent>
-      <InputConfig data={data} format="YAML" readOnly/>
-    </DialogContent>
-    <DialogActions>
-      <Button onClick={() => onClose?.()} color="primary">
-        close
-      </Button>
-    </DialogActions>
-  </Dialog>
-}
-InfoDialog.propTypes = {
-  title: PropTypes.string,
-  data: PropTypes.object,
-  DialogProps: PropTypes.object,
-  onClose: PropTypes.func
-}
-
-/**
- * Displays a list of information about the version, plugin package and plugin
- * entry points.
- */
-export const DistributionInfo = React.memo(({data}) => {
-  const [selected, setSelected] = useState()
-  const [title, setTitle] = useState()
-
-  const categories = useMemo(() => {
-    if (!data) return {}
-
-    const categories = {}
-    data.plugin_entry_points
-      .forEach((entryPoint) => {
-        let category = entryPoint.entry_point_type || entryPoint.plugin_type
-        // TODO: Schema plugins are recategorized as package plugins. This can be
-        // removed once all plugins have been migrated and we remove the old plugin
-        // models.
-        if (category === 'schema') {
-          category = 'schema_package'
-        }
-        category = category.replace('_', ' ')
-        if (categories[category]) {
-          categories[category].push(entryPoint)
-        } else {
-          categories[category] = [entryPoint]
-        }
-      })
-
-    Object.keys(categories).forEach(category => {
-      categories[category] = categories[category].sort((a, b) => {
-        const nameA = a.name
-        const nameB = b.name
-        return (nameA > nameB) ? 1 : -1
-      })
-    })
-
-    return categories
-  }, [data])
-
-  return data
-    ? <ul>
-        <li>version: {data.version}</li>
-        {data.plugin_packages
-          ? <li>{"plugin packages: "}
-            {data.plugin_packages.map(pluginPackage => <>
-              <Link key={pluginPackage.name} href="#" onClick={() => {
-                setSelected(pluginPackage)
-                setTitle('Plugin package')
-              }}>{pluginPackage.name}</Link>
-              {", "}
-            </>)}
-          </li>
-          : null
-        }
-      {Object.keys(categories)
-        .sort()
-        .map((category) => {
-          const entryPoints = categories[category]
-          return <li key={category}>
-            {`${pluralize(category, 2)}: `}
-            {entryPoints.map(entryPoint => <>
-              <Link key={entryPoint.id} href="#" onClick={() => {
-                setSelected(entryPoint)
-                setTitle('Plugin entry point')
-              }}>{entryPoint.id}</Link>
-              {", "}
-            </>)}
-          </li>
-      })}
-      <InfoDialog title={title} data={selected} onClose={() => setSelected(null)} />
-    </ul>
-    : 'Loading...'
-})
-
-DistributionInfo.propTypes = {
-  data: PropTypes.object
-}
-
 function CodeInfo({code, ...props}) {
   if (!code) {
     return null
@@ -312,9 +207,6 @@ const useStyles = makeStyles(theme => ({
     maxWidth: 1024,
     margin: 'auto',
     width: '100%'
-  },
-  header: {
-    margin: '24px 0px'
   }
 }))
 
@@ -524,12 +416,13 @@ export default function About() {
         with password \`password\`. The user \`sheldon.cooper@nomad-fairdi.tests.de\` is
         used for data that has no provenance with the original NOMAD CoE database.
         ` : ''}
+
+        ### About this version
+        - version: \`${info ? info.version : 'loading'}\`
+        - parsers: ${info ? info.parsers.join(', ') : 'loading'}
+        - normalizers: ${info ? info.normalizers.join(', ') : 'loading'}
         `}</Markdown>
       </Grid>
-      <Grid item xs={12}>
-        <Typography variant='h5' className={classes.header}>About this distribution</Typography>
-        <DistributionInfo data={info} />
-      </Grid>
     </Grid>
   </div>
 }
diff --git a/gui/src/components/nav/Routes.js b/gui/src/components/nav/Routes.js
index 2f2af38223feef9e390fcbff910bae24d56d92cd..abc69391b05cc4697850ed73b268f3851462e9e3 100644
--- a/gui/src/components/nav/Routes.js
+++ b/gui/src/components/nav/Routes.js
@@ -35,7 +35,7 @@ import APIs from '../APIs'
 import SearchPage from '../search/SearchPage'
 import { SearchContext } from '../search/SearchContext'
 import NorthPage, {help as NORTHHelp} from '../north/NorthPage'
-import { aitoolkitEnabled, appBase, oasis, encyclopediaBase, ui, apps } from '../../config'
+import { aitoolkitEnabled, appBase, oasis, encyclopediaBase, ui } from '../../config'
 import EntryQuery from '../entry/EntryQuery'
 import ResolvePID from '../entry/ResolvePID'
 import DatasetPage, { help as datasetHelp } from '../dataset/DatasetPage'
@@ -181,7 +181,7 @@ const toolkitRoute = (!oasis && aitoolkitEnabled)
     tooltip: 'Visit the NOMAD Artificial Intelligence Analytics Toolkit'
   }
 
-const searchRoutes = apps
+const searchRoutes = Object.values(ui?.apps?.options || {})
   .map((context) => {
     const routeMap = {
       entries: entryRoutes
diff --git a/gui/src/components/search/input/InputConfig.js b/gui/src/components/search/input/InputConfig.js
index 8fa80536428341c93156edc30ec57c3f229c1918..c151c25c6cce6773e623c6f8a157a004aa204a09 100644
--- a/gui/src/components/search/input/InputConfig.js
+++ b/gui/src/components/search/input/InputConfig.js
@@ -25,7 +25,7 @@ import YAML from 'yaml'
 /**
  * Form used for editing a YAML or JSON config.
  */
-const InputConfig = React.memo(({data, format, maxRows, minRows, onChange, error, onError, readOnly}) => {
+const InputConfig = React.memo(({data, format, maxRows, minRows, onChange, error, onError}) => {
   const controlledError = useRef(error !== undefined)
   const [serialized, setSerialized] = useState()
   const [errorInternal, setErrorInternal] = useState()
@@ -78,9 +78,6 @@ const InputConfig = React.memo(({data, format, maxRows, minRows, onChange, error
       minRows={minRows}
       value={serialized}
       onChange={handleChange}
-      InputProps={{
-        readOnly: readOnly
-      }}
     />
   )
 })
@@ -91,8 +88,7 @@ InputConfig.propTypes = {
   minRows: PropTypes.number,
   onChange: PropTypes.func,
   error: PropTypes.string,
-  onError: PropTypes.func,
-  readOnly: PropTypes.bool
+  onError: PropTypes.func
 }
 
 InputConfig.defaultProps = {
diff --git a/gui/src/config.js b/gui/src/config.js
index 05fc3302f37238ab9ca8b715682ad50a4b33f87a..9219bc27b62552e78c600f033589f0c1807d4348 100644
--- a/gui/src/config.js
+++ b/gui/src/config.js
@@ -88,13 +88,6 @@ export const apiBase = `${appBase}/api`
 export const northBase = urlAbs(window.nomadEnv.northBase)
 export const guiBase = process.env.PUBLIC_URL
 export const ui = normalizeConfig(window.nomadEnv.ui)
-export const entry_points = normalizeConfig(window.nomadEnv?.plugins?.entry_points)
-export const apps = Object.values(ui?.apps?.options || [])
-Object.values(entry_points?.options || [])
-  .filter(entry_point => entry_point.entry_point_type === 'app')
-  .forEach(entry_point => {
-    apps.push(entry_point.app)
-  })
 export const servicesUploadLimit = window.nomadEnv.servicesUploadLimit
 export const keycloakBase = window.nomadEnv.keycloakBase
 export const keycloakRealm = window.nomadEnv.keycloakRealm
diff --git a/gui/src/utils.js b/gui/src/utils.js
index 9b3b46cb7b5d14aafeb1138de96f9b519cb4361e..c4305bfbebd2e40985616962a758942c342a0e52 100644
--- a/gui/src/utils.js
+++ b/gui/src/utils.js
@@ -825,11 +825,7 @@ export function pluralize(word, count, inclusive, format = true, prefix) {
     'mainfile': 'mainfiles',
     'folder': 'folders',
     'has': 'have',
-    'activity': 'activities',
-    'parser': 'parsers',
-    'normalizer': 'normalizers',
-    'app': 'apps',
-    'package': 'packages'
+    'activity': 'activities'
   }
   const words = word.trim().split(" ")
   let lastWord = words[words.length - 1]
diff --git a/gui/tests/env.js b/gui/tests/env.js
index 65e35dc5bf93a41821aa50fc06f558eebab0c203..fd78f4ce95adbe6f8f68c6c35592e58aa0c657a5 100644
--- a/gui/tests/env.js
+++ b/gui/tests/env.js
@@ -3810,495 +3810,5 @@ window.nomadEnv = {
       "enabled": true
     },
     "example_uploads": {}
-  },
-  "plugins": {
-    "entry_points": {
-      "include": [
-        "schema/simulation/run",
-        "schema/simulation/workflow",
-        "parsers/vasp"
-      ],
-      "exclude": [],
-      "options": {
-        "normalizers/simulation/band_structure": {
-          "plugin_type": "normalizer",
-          "id": "normalizers/simulation/band_structure",
-          "name": "bandstructurenormalizer",
-          "description": "This is the normalizer for band structure in NOMAD.\n"
-        },
-        "normalizers/simulation/dos": {
-          "plugin_type": "normalizer",
-          "id": "normalizers/simulation/dos",
-          "name": "dosnormalizer",
-          "description": "This is the normalizer for DOS in NOMAD.\n"
-        },
-        "normalizers/simulation/soap": {
-          "plugin_type": "normalizer",
-          "id": "normalizers/simulation/soap",
-          "name": "soapnormalizer",
-          "description": "This is the normalizer for SOAP in NOMAD.\n"
-        },
-        "normalizers/simulation/spectra": {
-          "plugin_type": "normalizer",
-          "id": "normalizers/simulation/spectra",
-          "name": "spectranormalizer",
-          "description": "This is the normalizer for spectra in NOMAD.\n"
-        },
-        "normalizers/simulation/system": {
-          "plugin_type": "normalizer",
-          "id": "normalizers/simulation/system",
-          "name": "systemnormalizer",
-          "description": "This is the normalizer for system in NOMAD.\n"
-        },
-        "normalizers/simulation/workflow": {
-          "plugin_type": "normalizer",
-          "id": "normalizers/simulation/workflow",
-          "name": "simulationworkflownormalizer",
-          "description": "This is the normalizer for simulation workflows in NOMAD.\n"
-        },
-        "parsers/abacus": {
-          "plugin_type": "parser",
-          "id": "parsers/abacus",
-          "name": "parsers/abacus",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/abacus"
-        },
-        "parsers/abinit": {
-          "plugin_type": "parser",
-          "id": "parsers/abinit",
-          "name": "parsers/abinit",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/abinit"
-        },
-        "parsers/aflow": {
-          "plugin_type": "parser",
-          "id": "parsers/aflow",
-          "name": "parsers/aflow",
-          "plugin_source_code_url": "https://github.com/nomad-coe/workflow-parsers/tree/master/workflowparsers/aflow"
-        },
-        "parsers/amber": {
-          "plugin_type": "parser",
-          "id": "parsers/amber",
-          "name": "parsers/amber",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/amber"
-        },
-        "parsers/ams": {
-          "plugin_type": "parser",
-          "id": "parsers/ams",
-          "name": "parsers/ams",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/ams"
-        },
-        "parsers/asap": {
-          "plugin_type": "parser",
-          "id": "parsers/asap",
-          "name": "parsers/asap",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/asap"
-        },
-        "parsers/asr": {
-          "plugin_type": "parser",
-          "id": "parsers/asr",
-          "name": "parsers/asr",
-          "plugin_source_code_url": "https://github.com/nomad-coe/workflow-parsers/tree/master/workflowparsers/asr"
-        },
-        "parsers/atk": {
-          "plugin_type": "parser",
-          "id": "parsers/atk",
-          "name": "parsers/atk",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/atk"
-        },
-        "parsers/atomate": {
-          "plugin_type": "parser",
-          "id": "parsers/atomate",
-          "name": "parsers/atomate",
-          "plugin_source_code_url": "https://github.com/nomad-coe/workflow-parsers/tree/master/workflowparsers/automate"
-        },
-        "parsers/bigdft": {
-          "plugin_type": "parser",
-          "id": "parsers/bigdft",
-          "name": "parsers/bigdft",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/bigdft"
-        },
-        "parsers/bopfox": {
-          "plugin_type": "parser",
-          "id": "parsers/bopfox",
-          "name": "parsers/bopfox",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/bobfox"
-        },
-        "parsers/castep": {
-          "plugin_type": "parser",
-          "id": "parsers/castep",
-          "name": "parsers/castep",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/castep"
-        },
-        "parsers/charmm": {
-          "plugin_type": "parser",
-          "id": "parsers/charmm",
-          "name": "parsers/charmm",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/charmm"
-        },
-        "parsers/chemotion/chemotion": {
-          "plugin_type": "parser",
-          "id": "parsers/chemotion/chemotion",
-          "name": "parsers/chemotion"
-        },
-        "parsers/cp2k": {
-          "plugin_type": "parser",
-          "id": "parsers/cp2k",
-          "name": "parsers/cp2k",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/cp2k"
-        },
-        "parsers/cpmd": {
-          "plugin_type": "parser",
-          "id": "parsers/cpmd",
-          "name": "parsers/cpmd",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/cpmd"
-        },
-        "parsers/crystal": {
-          "plugin_type": "parser",
-          "id": "parsers/crystal",
-          "name": "parsers/crystal",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/crystal"
-        },
-        "parsers/dftbplus": {
-          "plugin_type": "parser",
-          "id": "parsers/dftbplus",
-          "name": "parsers/dftbplus",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/dftplus"
-        },
-        "parsers/dlpoly": {
-          "plugin_type": "parser",
-          "id": "parsers/dlpoly",
-          "name": "parsers/dl-poly",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/dlpoly"
-        },
-        "parsers/dmol3": {
-          "plugin_type": "parser",
-          "id": "parsers/dmol3",
-          "name": "parsers/dmol",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/dmol3"
-        },
-        "parsers/edmft": {
-          "plugin_type": "parser",
-          "id": "parsers/edmft",
-          "name": "parsers/edmft",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/edmft"
-        },
-        "parsers/eelsdbparser": {
-          "plugin_type": "parser",
-          "id": "parsers/eelsdbparser",
-          "name": "parsers/eels",
-          "plugin_source_code_url": "https://github.com/nomad-coe/nomad-parser-eelsdb"
-        },
-        "parsers/elabftw/elabftw": {
-          "plugin_type": "parser",
-          "id": "parsers/elabftw/elabftw",
-          "name": "parsers/elabftw",
-          "plugin_source_code_url": "https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-FAIR/-/tree/develop/nomad/parsing/elabftw"
-        },
-        "parsers/elastic": {
-          "plugin_type": "parser",
-          "id": "parsers/elastic",
-          "name": "parsers/elastic",
-          "plugin_source_code_url": "https://github.com/nomad-coe/workflow-parsers/tree/master/workflowparsers/elastic"
-        },
-        "parsers/elk": {
-          "plugin_type": "parser",
-          "id": "parsers/elk",
-          "name": "parsers/elk",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/elk"
-        },
-        "parsers/exciting": {
-          "plugin_type": "parser",
-          "id": "parsers/exciting",
-          "name": "parsers/exciting",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/exciting"
-        },
-        "parsers/fhi-aims": {
-          "plugin_type": "parser",
-          "id": "parsers/fhi-aims",
-          "name": "parsers/fhi-aims",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/fhiaims"
-        },
-        "parsers/fhivibes": {
-          "plugin_type": "parser",
-          "id": "parsers/fhivibes",
-          "name": "parsers/fhi-vibes",
-          "plugin_source_code_url": "https://github.com/nomad-coe/workflow-parsers/tree/master/workflowparsers/fhivibes"
-        },
-        "parsers/fleur": {
-          "plugin_type": "parser",
-          "id": "parsers/fleur",
-          "name": "parsers/fleur",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/fleur"
-        },
-        "parsers/fplo": {
-          "plugin_type": "parser",
-          "id": "parsers/fplo",
-          "name": "parsers/fplo",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/fplo"
-        },
-        "parsers/gamess": {
-          "plugin_type": "parser",
-          "id": "parsers/gamess",
-          "name": "parsers/gamess",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/gamess"
-        },
-        "parsers/gaussian": {
-          "plugin_type": "parser",
-          "id": "parsers/gaussian",
-          "name": "parsers/gaussian",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/gaussian"
-        },
-        "parsers/gpaw": {
-          "plugin_type": "parser",
-          "id": "parsers/gpaw",
-          "name": "parsers/gpaw",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/gpaw"
-        },
-        "parsers/gromacs": {
-          "plugin_type": "parser",
-          "id": "parsers/gromacs",
-          "name": "parsers/gromacs",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/gromacs"
-        },
-        "parsers/gromos": {
-          "plugin_type": "parser",
-          "id": "parsers/gromos",
-          "name": "parsers/gromos",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/gromos"
-        },
-        "parsers/gulp": {
-          "plugin_type": "parser",
-          "id": "parsers/gulp",
-          "name": "parsers/gulp",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/gulp"
-        },
-        "parsers/h5md": {
-          "plugin_type": "parser",
-          "id": "parsers/h5md",
-          "name": "parsers/h5md"
-        },
-        "parsers/lammps": {
-          "plugin_type": "parser",
-          "id": "parsers/lammps",
-          "name": "parsers/lammps",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/lammps"
-        },
-        "parsers/libatoms": {
-          "plugin_type": "parser",
-          "id": "parsers/libatoms",
-          "name": "parsers/lib-atoms",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/libatoms"
-        },
-        "parsers/lobster": {
-          "plugin_type": "parser",
-          "id": "parsers/lobster",
-          "name": "parsers/lobster",
-          "plugin_source_code_url": "https://github.com/nomad-coe/workflow-parsers/tree/master/workflowparsers/lobster"
-        },
-        "parsers/magres": {
-          "plugin_type": "parser",
-          "id": "parsers/magres",
-          "name": "parsers/magres",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/magres"
-        },
-        "parsers/molcas": {
-          "plugin_type": "parser",
-          "id": "parsers/molcas",
-          "name": "parsers/molcas",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/molcas"
-        },
-        "parsers/mopac": {
-          "plugin_type": "parser",
-          "id": "parsers/mopac",
-          "name": "parsers/mopac",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/mopac"
-        },
-        "parsers/namd": {
-          "plugin_type": "parser",
-          "id": "parsers/namd",
-          "name": "parsers/namd",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/namd"
-        },
-        "parsers/nexus": {
-          "plugin_type": "parser",
-          "id": "parsers/nexus",
-          "name": "parsers/nexus",
-          "plugin_source_code_url": "https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-FAIR/-/tree/develop/nomad/parsing/nexus"
-        },
-        "parsers/nwchem": {
-          "plugin_type": "parser",
-          "id": "parsers/nwchem",
-          "name": "parsers/nwchem",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/nwchem"
-        },
-        "parsers/ocean": {
-          "plugin_type": "parser",
-          "id": "parsers/ocean",
-          "name": "parsers/ocean",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/ocean"
-        },
-        "parsers/octopus": {
-          "plugin_type": "parser",
-          "id": "parsers/octopus",
-          "name": "parsers/octopus",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/octopus"
-        },
-        "parsers/onetep": {
-          "plugin_type": "parser",
-          "id": "parsers/onetep",
-          "name": "parsers/onetep",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/onetep"
-        },
-        "parsers/openkim": {
-          "plugin_type": "parser",
-          "id": "parsers/openkim",
-          "name": "parsers/openkim",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/databaseparsers/openkim"
-        },
-        "parsers/openmx": {
-          "plugin_type": "parser",
-          "id": "parsers/openmx",
-          "name": "parsers/openmx",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/openmx"
-        },
-        "parsers/orca": {
-          "plugin_type": "parser",
-          "id": "parsers/orca",
-          "name": "parsers/orca",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/orca"
-        },
-        "parsers/phonopy": {
-          "plugin_type": "parser",
-          "id": "parsers/phonopy",
-          "name": "parsers/phonopy",
-          "plugin_source_code_url": "https://github.com/nomad-coe/workflow-parsers/tree/master/workflowparsers/phonopy"
-        },
-        "parsers/psi4": {
-          "plugin_type": "parser",
-          "id": "parsers/psi4",
-          "name": "parsers/psi4",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/psi4"
-        },
-        "parsers/qball": {
-          "plugin_type": "parser",
-          "id": "parsers/qball",
-          "name": "parsers/qball",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/qball"
-        },
-        "parsers/qbox": {
-          "plugin_type": "parser",
-          "id": "parsers/qbox",
-          "name": "parsers/qbox",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/qbox"
-        },
-        "parsers/quantum_espresso_epw": {
-          "plugin_type": "parser",
-          "id": "parsers/quantum_espresso_epw",
-          "name": "parsers/quantumespressoepw",
-          "plugin_source_code_url": "https://github.com/nomad-coe/workflow-parsers/tree/master/workflowparsers/quantum_espresso_epw"
-        },
-        "parsers/quantum_espresso_phonon": {
-          "plugin_type": "parser",
-          "id": "parsers/quantum_espresso_phonon",
-          "name": "parsers/quantumespressophonon",
-          "plugin_source_code_url": "https://github.com/nomad-coe/workflow-parsers/tree/master/workflowparsers/quantum_espresso_phonon"
-        },
-        "parsers/quantum_espresso_xspectra": {
-          "plugin_type": "parser",
-          "id": "parsers/quantum_espresso_xspectra",
-          "name": "parsers/quantumespressoxspectra",
-          "plugin_source_code_url": "https://github.com/nomad-coe/workflow-parsers/tree/master/workflowparsers/quantum_espresso_xpectra"
-        },
-        "parsers/quantumespresso": {
-          "plugin_type": "parser",
-          "id": "parsers/quantumespresso",
-          "name": "parsers/quantumespresso",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/quantumespresso"
-        },
-        "parsers/siesta": {
-          "plugin_type": "parser",
-          "id": "parsers/siesta",
-          "name": "parsers/siesta",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/siesta"
-        },
-        "parsers/soliddmft": {
-          "plugin_type": "parser",
-          "id": "parsers/soliddmft",
-          "name": "parsers/soliddmft",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/soliddmft"
-        },
-        "parsers/tbstudio": {
-          "plugin_type": "parser",
-          "id": "parsers/tbstudio",
-          "name": "parsers/tbstudio"
-        },
-        "parsers/tinker": {
-          "plugin_type": "parser",
-          "id": "parsers/tinker",
-          "name": "parsers/tinker",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/tinker"
-        },
-        "parsers/turbomole": {
-          "plugin_type": "parser",
-          "id": "parsers/turbomole",
-          "name": "parsers/turbomole",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/turbomole"
-        },
-        "parsers/vasp": {
-          "plugin_type": "parser",
-          "id": "parsers/vasp",
-          "name": "parsers/vasp",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/vasp"
-        },
-        "parsers/w2dynamics": {
-          "plugin_type": "parser",
-          "id": "parsers/w2dynamics",
-          "name": "parsers/w2dynamics",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/w2dynamics"
-        },
-        "parsers/wannier90": {
-          "plugin_type": "parser",
-          "id": "parsers/wannier90",
-          "name": "parsers/wannier90",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/wannier90"
-        },
-        "parsers/wien2k": {
-          "plugin_type": "parser",
-          "id": "parsers/wien2k",
-          "name": "parsers/wien2k",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/wien2k"
-        },
-        "parsers/xtb": {
-          "plugin_type": "parser",
-          "id": "parsers/xtb",
-          "name": "parsers/xtb",
-          "plugin_source_code_url": "https://github.com/nomad-coe/atomistic-parsers/tree/develop/atomisticparsers/xtb"
-        },
-        "parsers/yambo": {
-          "plugin_type": "parser",
-          "id": "parsers/yambo",
-          "name": "parsers/yambo",
-          "plugin_source_code_url": "https://github.com/nomad-coe/electronic-parsers/tree/develop/electronicparsers/yambo"
-        },
-        "schema/nomad-perovskite-solar-cells-database/perovskite_solar_cell_database": {
-          "plugin_type": "schema",
-          "id": "schema/nomad-perovskite-solar-cells-database/perovskite_solar_cell_database",
-          "name": "perovskite_solar_cell_database",
-          "description": "A NOMAD plugin containing the schema for the Perovskite Solar Cell Database."
-        },
-        "schema/simulation/run": {
-          "plugin_type": "schema",
-          "id": "schema/simulation/run",
-          "name": "runschema",
-          "description": "Run schema plugin for NOMAD.\n"
-        },
-        "schema/simulation/workflow": {
-          "plugin_type": "schema",
-          "id": "schema/simulation/workflow",
-          "name": "simulationworkflowschema",
-          "description": "This is a collection of schemas for various types of simulation workflows.\n"
-        }
-      }
-    },
-    "plugin_packages": {}
   }
 }
diff --git a/nomad/app/v1/routers/info.py b/nomad/app/v1/routers/info.py
index a44825ecc92ce1d070f717939266b1325b3c34cc..2ded9bafd99323954d4fe2440727462763a064ed 100644
--- a/nomad/app/v1/routers/info.py
+++ b/nomad/app/v1/routers/info.py
@@ -89,14 +89,6 @@ class InfoModel(BaseModel):
     metainfo_packages: List[str]
     codes: List[CodeInfoModel]
     normalizers: List[str]
-    plugin_entry_points: List[dict] = Field(
-        None,
-        desciption='List of plugin entry points that are activated in this deployment.',
-    )
-    plugin_packages: List[dict] = Field(
-        None,
-        desciption='List of plugin packages that are installed in this deployment.',
-    )
     statistics: StatisticsModel = Field(None, description='General NOMAD statistics')
     search_quantities: dict
     version: str
@@ -160,9 +152,6 @@ async def get_info():
     parser_names = sorted(
         [re.sub(r'^(parsers?|missing)/', '', key) for key in parsers.parser_dict.keys()]
     )
-
-    config.load_plugins()
-
     return InfoModel(
         **{
             'parsers': parser_names,
@@ -186,14 +175,6 @@ async def get_info():
             'normalizers': [
                 normalizer.__name__ for normalizer in normalizing.normalizers
             ],
-            'plugin_entry_points': [
-                entry_point.dict_safe()
-                for entry_point in config.plugins.entry_points.filtered_values()
-            ],
-            'plugin_packages': [
-                plugin_package.dict()
-                for plugin_package in config.plugins.plugin_packages.values()
-            ],
             'statistics': statistics(),
             'search_quantities': {
                 s.qualified_name: {
diff --git a/nomad/cli/dev.py b/nomad/cli/dev.py
index 3d6baf264c33ecbba15e9346edfd1110b160f34e..435008cb5202117871470bd188a4b6fe84a67c30 100644
--- a/nomad/cli/dev.py
+++ b/nomad/cli/dev.py
@@ -216,13 +216,6 @@ def get_gui_config() -> str:
     """
     from nomad.config import config
 
-    config.load_plugins()
-    plugins = config.plugins.dict(exclude_unset=True)
-    for key in plugins['entry_points']['options'].keys():
-        plugins['entry_points']['options'][key] = config.plugins.entry_points.options[
-            key
-        ].dict_safe()
-
     data = {
         'appBase': config.ui.app_base,
         'northBase': config.ui.north_base,
@@ -240,7 +233,6 @@ def get_gui_config() -> str:
         'servicesUploadLimit': config.services.upload_limit,
         'appTokenMaxExpiresIn': config.services.app_token_max_expires_in,
         'ui': config.ui.dict(exclude_none=True) if config.ui else {},
-        'plugins': plugins,
     }
 
     return f'window.nomadEnv = {json.dumps(data, indent=2)}'
diff --git a/nomad/config/__init__.py b/nomad/config/__init__.py
index c1851e85b2d19550a32be7c242f2af3c9aab2729..e274b5069784f406cbbea26f7a07e5041c60c266 100644
--- a/nomad/config/__init__.py
+++ b/nomad/config/__init__.py
@@ -117,8 +117,7 @@ def _merge(*args) -> Dict[str, Any]:
 
     root = args[0]
     for config in args[1:]:
-        if config:
-            root = merge_dicts(root, config)
+        root = merge_dicts(root, config)
     return root
 
 
diff --git a/nomad/config/models/config.py b/nomad/config/models/config.py
index 71e2239af4e6488f08faaa8a1410b20253183485..d82252db45ed87f4b20c7bf7c37c4d8f9aeaa41c 100644
--- a/nomad/config/models/config.py
+++ b/nomad/config/models/config.py
@@ -17,14 +17,13 @@
 #
 
 import warnings
-import sys
 import os
 import logging
-from importlib.metadata import version, metadata
+from importlib.metadata import version
 
 import yaml
 from typing import List, Union, Optional, Dict, Any
-from pydantic import Field, root_validator, validator
+from pydantic import Field, root_validator, validator, parse_obj_as
 import pkgutil
 
 try:
@@ -33,17 +32,11 @@ except Exception:  # noqa
     # package is not installed
     pass
 
-if sys.version_info < (3, 10):
-    from importlib_metadata import entry_points
-else:
-    from importlib.metadata import entry_points
-
-
 from .common import (
     ConfigBaseModel,
     Options,
 )
-from .plugins import Plugins, EntryPointType, PluginPackage
+from .plugins import Plugins
 from .north import NORTH
 from .ui import UI
 
@@ -1008,24 +1001,6 @@ class Config(ConfigBaseModel):
 
         return values
 
-    def get_plugin_entry_point(self, id: str) -> EntryPointType:
-        """Returns the plugin entry point with the given id. It will
-        contain also any overrides included through nomad.yaml.
-
-        Args:
-            id: The entry point identifier. Use the identifier given in the
-            plugin package pyproject.toml.
-        """
-        try:
-            return self.plugins.entry_points.options[id]
-        except KeyError:
-            raise KeyError(
-                f'Could not find plugin entry point with id "{id}". Make sure that '
-                'the plugin package with an up-to-date pyproject.toml is installed and '
-                'that you are using the entry point id given in the plugin '
-                'pyproject.toml'
-            )
-
     def load_plugins(self):
         """Used to lazy-load the plugins. We cannot instantiate the plugins
         during the initialization of the nomad.config package, because it may
@@ -1038,85 +1013,38 @@ class Config(ConfigBaseModel):
         cached_property decorator to the 'plugins' field instead of using this
         function.
         """
-        from nomad.config import _plugins, _merge
-        from nomad.config.models.plugins import Parser, Normalizer, Schema
-
         if self.plugins is None:
-            # Any plugins defined at the 'plugin' level are lifted to the
-            # 'plugin.entry_points'.
-            entry_points_config = _plugins.setdefault('entry_points', {})
-            include_old = _plugins.get('include')
-            include_new = entry_points_config.get('include')
-            if include_old is not None:
-                if include_new is None:
-                    entry_points_config['include'] = include_old
-                else:
-                    entry_points_config['include'].extend(include_old)
-            entry_points_config.setdefault('exclude', []).extend(
-                _plugins.get('exclude', [])
-            )
-            entry_points_config.setdefault('options', {}).update(
-                _plugins.get('options', {})
-            )
+            from nomad.config import _plugins
+            from nomad.config.models.plugins import Plugin
 
-            # Handle plugin entry_points (new plugin mechanism)
-            plugin_entry_point_ids = set()
-            plugin_entry_points = entry_points(group='nomad.plugin')
-            plugin_packages = {}
-
-            for entry_point in plugin_entry_points:
-                key = entry_point.value
-                if key in plugin_entry_point_ids:
-                    raise ValueError(
-                        f'Could not load plugins due to duplicate entry_point name: "{key}".'
-                    )
-                package_name = entry_point.value.split('.', 1)[0]
-                config_override = (
-                    _plugins.get('entry_points', {}).get('options', {}).get(key, {})
-                )
-                config_override['id'] = key
-                config_instance = entry_point.load()
-                package_metadata = metadata(package_name)
-                url_list = package_metadata.get_all('Project-URL')
-                url_dict = {}
-                for url in url_list:
-                    name, value = url.split(',')
-                    url_dict[name.lower()] = value.strip()
-                if package_name not in plugin_packages:
-                    plugin_package = PluginPackage(
-                        name=package_name,
-                        description=package_metadata.get('Summary'),
-                        version=version(package_name),
-                        homepage=url_dict.get('homepage'),
-                        documentation=url_dict.get('documentation'),
-                        repository=url_dict.get('repository'),
-                        entry_points=[key],
-                    )
-                    plugin_packages[package_name] = plugin_package
-                else:
-                    plugin_packages[package_name].entry_points.append(key)
-                config_default = config_instance.dict(exclude_unset=True)
-                config_default['plugin_package'] = package_name
-                config_class = config_instance.__class__
-                config_final = config_class.parse_obj(
-                    _merge(config_default, config_override)
-                )
-                _plugins['entry_points']['options'][key] = config_final
-                plugin_entry_point_ids.add(key)
-            _plugins['plugin_packages'] = plugin_packages
-
-            # Handle plugins defined in nomad.yaml (old plugin mechanism)
-            def load_plugin_yaml(name, values: Dict[str, Any]):
+            def load_plugin(values: Dict[str, Any]):
                 """Loads plugin metadata from nomad_plugin.yaml"""
                 python_package = values.get('python_package')
                 if not python_package:
-                    raise ValueError(
-                        f'Could not find python_package for plugin entry point: {name}.'
-                    )
+                    raise ValueError('Python plugins must provide a python_package.')
 
                 package_path = values.get('package_path')
                 if package_path is None:
-                    package_path = get_package_path(python_package)
+                    try:
+                        # We try to deduce the package path from the top-level package
+                        package_path_segments = python_package.split('.')
+                        root_package = package_path_segments[0]
+                        package_dirs = package_path_segments[1:]
+                        package_path = os.path.join(
+                            os.path.dirname(
+                                pkgutil.get_loader(root_package).get_filename()  # type: ignore
+                            ),
+                            *package_dirs,
+                        )
+                        if not os.path.isdir(package_path):
+                            # We could not find it this way. Let's try to official way
+                            package_path = os.path.dirname(
+                                pkgutil.get_loader(python_package).get_filename()  # type: ignore
+                            )
+                    except Exception as e:
+                        raise ValueError(
+                            f'The python package {python_package} cannot be loaded.', e
+                        )
                     values['package_path'] = package_path
 
                 metadata_path = os.path.join(package_path, 'nomad_plugin.yaml')
@@ -1136,41 +1064,5 @@ class Config(ConfigBaseModel):
                 return values
 
             for key, plugin in _plugins['options'].items():
-                if key not in plugin_entry_point_ids:
-                    plugin_config = load_plugin_yaml(key, plugin)
-                    plugin_config['id'] = key
-                    plugin_class = {
-                        'parser': Parser,
-                        'normalizer': Normalizer,
-                        'schema': Schema,
-                    }.get(plugin_config['plugin_type'])
-                    _plugins['entry_points']['options'][key] = plugin_class.parse_obj(
-                        plugin_config
-                    )
-
+                _plugins['options'][key] = parse_obj_as(Plugin, load_plugin(plugin))
             self.plugins = Plugins.parse_obj(_plugins)
-
-
-def get_package_path(package_name: str) -> str:
-    """Given a python package name, returns the filepath of the package root folder."""
-    package_path = None
-    try:
-        # We try to deduce the package path from the top-level package
-        package_path_segments = package_name.split('.')
-        root_package = package_path_segments[0]
-        package_dirs = package_path_segments[1:]
-        package_path = os.path.join(
-            os.path.dirname(
-                pkgutil.get_loader(root_package).get_filename()  # type: ignore
-            ),
-            *package_dirs,
-        )
-        if not os.path.isdir(package_path):
-            # We could not find it this way. Let's try to official way
-            package_path = os.path.dirname(
-                pkgutil.get_loader(python_package).get_filename()  # type: ignore
-            )
-    except Exception as e:
-        raise ValueError(f'The python package {package_name} cannot be loaded.', e)
-
-    return package_path
diff --git a/nomad/config/models/plugins.py b/nomad/config/models/plugins.py
index d81126bde307d25ddb7927f14786760fb9f46b87..e4797fe8b5247972cf603cebafdd7d82fca9a0a3 100644
--- a/nomad/config/models/plugins.py
+++ b/nomad/config/models/plugins.py
@@ -17,154 +17,12 @@
 #
 
 import sys
-from abc import ABCMeta, abstractmethod
 import importlib
-from typing import Optional, Dict, Union, List, Literal, TYPE_CHECKING
+from typing_extensions import Annotated
+from typing import Optional, Dict, Union, List, Literal
 from pydantic import BaseModel, Field
 
 from .common import Options
-from .ui import App
-
-if TYPE_CHECKING:
-    from nomad.metainfo import SchemaPackage
-    from nomad.normalizing import Normalizer as NormalizerBaseClass
-    from nomad.parsing import Parser as ParserBaseClass
-
-
-class EntryPoint(BaseModel):
-    """Base model for a NOMAD plugin entry points."""
-
-    id: Optional[str] = Field(
-        description='Unique identifier corresponding to the entry point name. Automatically set to the plugin entry point name in pyproject.toml.'
-    )
-    entry_point_type: str = Field(description='Determines the entry point type.')
-    name: Optional[str] = Field(description='Name of the plugin entry point.')
-    description: Optional[str] = Field(
-        description='A human readable description of the plugin entry point.'
-    )
-    plugin_package: Optional[str] = Field(
-        description='The plugin package from which this entry points comes from.'
-    )
-
-    def dict_safe(self):
-        """Used to serialize the non-confidential parts of a plugin model. This
-        function can be overridden in subclasses to expose more information.
-        """
-        return self.dict(include=EntryPoint.__fields__.keys(), exclude_none=True)
-
-
-class AppEntryPoint(EntryPoint):
-    entry_point_type: Literal['app'] = Field(
-        'app', description='Determines the entry point type.'
-    )
-    app: App = Field(description='The app configuration.')
-
-    def dict_safe(self):
-        return self.dict(include=AppEntryPoint.__fields__.keys(), exclude_none=True)
-
-
-class SchemaPackageEntryPoint(EntryPoint, metaclass=ABCMeta):
-    entry_point_type: Literal['schema_package'] = Field(
-        'schema_package', description='Specifies the entry point type.'
-    )
-
-    @abstractmethod
-    def load(self) -> 'SchemaPackage':
-        """Used to lazy-load a schema package instance. You should override this
-        method in your subclass. Note that any Python module imports required
-        for the schema package should be done within this function as well."""
-        pass
-
-
-class NormalizerEntryPoint(EntryPoint, metaclass=ABCMeta):
-    entry_point_type: Literal['normalizer'] = Field(
-        'normalizer', description='Determines the entry point type.'
-    )
-
-    @abstractmethod
-    def load(self) -> 'NormalizerBaseClass':
-        """Used to lazy-load a normalizer instance. You should override this
-        method in your subclass. Note that any Python module imports required
-        for the normalizer class should be done within this function as well."""
-        pass
-
-
-class ParserEntryPoint(EntryPoint, metaclass=ABCMeta):
-    entry_point_type: Literal['parser'] = Field(
-        'parser', description='Determines the entry point type.'
-    )
-    level: int = Field(
-        0,
-        description="""
-        The order by which the parser is executed with respect to other parsers.
-    """,
-    )
-
-    mainfile_contents_re: Optional[str] = Field(
-        description="""
-        A regular expression that is applied the content of a potential mainfile.
-        If this expression is given, the parser is only considered for a file, if the
-        expression matches.
-    """
-    )
-    mainfile_name_re: str = Field(
-        r'.*',
-        description="""
-        A regular expression that is applied the name of a potential mainfile.
-        If this expression is given, the parser is only considered for a file, if the
-        expression matches.
-    """,
-    )
-    mainfile_mime_re: str = Field(
-        r'.*',
-        description="""
-        A regular expression that is applied the mime type of a potential
-        mainfile. If this expression is given, the parser is only considered
-        for a file, if the expression matches.
-    """,
-    )
-    mainfile_binary_header: Optional[bytes] = Field(
-        description="""
-        Matches a binary file if the given bytes are included in the file.
-    """,
-        exclude=True,
-    )
-    mainfile_binary_header_re: Optional[bytes] = Field(
-        description="""
-        Matches a binary file if the given binary regular expression bytes matches the
-        file contents.
-    """,
-        exclude=True,
-    )
-    mainfile_alternative: bool = Field(
-        False,
-        description="""
-        If True, the parser only matches a file, if no other file in the same directory
-        matches a parser.
-    """,
-    )
-    mainfile_contents_dict: Optional[dict] = Field(
-        description="""
-        Is used to match structured data files like JSON or HDF5.
-    """
-    )
-    supported_compressions: List[str] = Field(
-        [],
-        description="""
-        Files compressed with the given formats (e.g. xz, gz) are uncompressed and
-        matched like normal files.
-    """,
-    )
-
-    @abstractmethod
-    def load(self) -> 'ParserBaseClass':
-        """Used to lazy-load a parser instance. You should override this method
-        in your subclass. Note that any Python module imports required for the
-        parser class should be done within this function as well."""
-        pass
-
-    def dict_safe(self):
-        return self.dict(include=ParserEntryPoint.__fields__.keys(), exclude_none=True)
 
 
 class PluginBase(BaseModel):
@@ -175,10 +33,6 @@ class PluginBase(BaseModel):
     Parser or Schema.
     """
 
-    plugin_type: str = Field(
-        description='The type of the plugin.',
-    )
-    id: Optional[str] = Field(description='The unique identifier for this plugin.')
     name: str = Field(
         description='A short descriptive human readable name for the plugin.'
     )
@@ -192,12 +46,6 @@ class PluginBase(BaseModel):
         description='The URL of the plugins main source code repository.'
     )
 
-    def dict_safe(self):
-        """Used to serialize the non-confidential parts of a plugin model. This
-        function can be overridden in subclasses to expose more information.
-        """
-        return self.dict(include=PluginBase.__fields__.keys(), exclude_none=True)
-
 
 class PythonPluginBase(PluginBase):
     """
@@ -325,15 +173,13 @@ class Parser(PythonPluginBase):
     mainfile_binary_header: Optional[bytes] = Field(
         description="""
         Matches a binary file if the given bytes are included in the file.
-    """,
-        exclude=True,
+    """
     )
     mainfile_binary_header_re: Optional[bytes] = Field(
         description="""
         Matches a binary file if the given binary regular expression bytes matches the
         file contents.
-    """,
-        exclude=True,
+    """
     )
     mainfile_alternative: bool = Field(
         False,
@@ -385,7 +231,6 @@ class Parser(PythonPluginBase):
         from nomad.parsing.parser import MatchingParserInterface
 
         data = self.dict()
-        del data['id']
         del data['description']
         del data['python_package']
         del data['plugin_type']
@@ -396,57 +241,13 @@ class Parser(PythonPluginBase):
         return MatchingParserInterface(**data)
 
 
-EntryPointType = Union[
-    Schema,
-    Normalizer,
-    Parser,
-    SchemaPackageEntryPoint,
-    ParserEntryPoint,
-    NormalizerEntryPoint,
-    AppEntryPoint,
+Plugin = Annotated[
+    Union[Schema, Normalizer, Parser], Field(discriminator='plugin_type')
 ]
 
 
-class EntryPoints(Options):
-    options: Dict[str, EntryPointType] = Field(
-        dict(), description='The available plugin entry points.'
-    )
-
-
-class PluginPackage(BaseModel):
-    name: str = Field(
-        description='Name of the plugin Python package, read from pyproject.toml.'
-    )
-    description: Optional[str] = Field(
-        description='Package description, read from pyproject.toml.'
-    )
-    version: Optional[str] = Field(
-        description='Plugin package version, read from pyproject.toml.'
-    )
-    homepage: Optional[str] = Field(
-        description='Link to the plugin package homepage, read from pyproject.toml.'
-    )
-    documentation: Optional[str] = Field(
-        description='Link to the plugin package documentation page, read from pyproject.toml.'
-    )
-    repository: Optional[str] = Field(
-        description='Link to the plugin package source code repository, read from pyproject.toml.'
-    )
-    entry_points: List[str] = Field(
-        description='List of entry point ids contained in this package, read form pyproject.toml'
-    )
-
-
-class Plugins(BaseModel):
-    entry_points: EntryPoints = Field(
-        description='Used to control plugin entry points.'
-    )
-    plugin_packages: Dict[str, PluginPackage] = Field(
-        description="""
-        Contains the installed installed plugin packages with the package name
-        used as a key. This is autogenerated and should not be modified.
-        """
-    )
+class Plugins(Options):
+    options: Dict[str, Plugin] = Field(dict(), description='The available plugin.')
 
 
 def add_plugin(plugin: Schema) -> None:
@@ -458,7 +259,7 @@ def add_plugin(plugin: Schema) -> None:
         sys.path.insert(0, plugin.package_path)
 
     # Add plugin to config
-    config.plugins.entry_points.options[plugin.key] = plugin
+    config.plugins.options[plugin.key] = plugin
 
     # Add plugin to Package registry
     package = importlib.import_module(plugin.python_package)
@@ -482,7 +283,7 @@ def remove_plugin(plugin) -> None:
         pass
 
     # Remove package as plugin
-    del config.plugins.entry_points.options[plugin.key]
+    del config.plugins.options[plugin.key]
 
     # Remove plugin from Package registry
     package = importlib.import_module(plugin.python_package).m_package
diff --git a/nomad/datamodel/__init__.py b/nomad/datamodel/__init__.py
index 370ab0775e1845ed24c84a8fa833a0b3a9c62cc5..582a8ed56a5299ad4e834f0c7d058e83a6df79a5 100644
--- a/nomad/datamodel/__init__.py
+++ b/nomad/datamodel/__init__.py
@@ -34,7 +34,6 @@ from .optimade import OptimadeEntry, Species
 from .metainfo import m_env
 from .results import Results
 from .data import EntryData, ArchiveSection
-from nomad.config.models.plugins import SchemaPackageEntryPoint
 from .context import Context, ClientContext, ServerContext
 
 m_env.m_add_sub_section(
@@ -63,11 +62,9 @@ def all_metainfo_packages():
     from nomad.config import config
 
     config.load_plugins()
-    for entry_point in config.plugins.entry_points.filtered_values():
-        if isinstance(entry_point, PythonPluginBase):
-            entry_point.import_python_package()
-        if isinstance(entry_point, SchemaPackageEntryPoint):
-            entry_point.load()
+    for plugin in config.plugins.filtered_values():
+        if isinstance(plugin, PythonPluginBase):
+            plugin.import_python_package()
 
     # Importing the parsers will also make sure that related schemas will be imported
     # even if they are not part of the plugin's python package as this will import
diff --git a/nomad/datamodel/data.py b/nomad/datamodel/data.py
index 5c4d738df7a446dadcc534f19fccf1fb3b7c7a3c..73595a44ed730023f0e4d86e009777ee32267c9a 100644
--- a/nomad/datamodel/data.py
+++ b/nomad/datamodel/data.py
@@ -257,4 +257,3 @@ class AuthorReference(Reference):
 
 author_reference = AuthorReference()
 predefined_datatypes['Author'] = author_reference
-Schema = EntryData
diff --git a/nomad/datamodel/metainfo/__init__.py b/nomad/datamodel/metainfo/__init__.py
index 5df06327f442fab002bdd6318ae66c666f4bd228..d13c4beaf48778cd391dd3ae24b6624a538d009d 100644
--- a/nomad/datamodel/metainfo/__init__.py
+++ b/nomad/datamodel/metainfo/__init__.py
@@ -48,13 +48,13 @@ class SchemaInterface:
 
 simulationworkflowschema, runschema = None, None
 config.load_plugins()
-for entry_point in config.plugins.entry_points.filtered_values():
-    if isinstance(entry_point, Schema):
-        if entry_point.name == 'simulationworkflowschema':
-            simulationworkflowschema = SchemaInterface(entry_point.python_package)
-        elif entry_point.name == 'runschema':
-            runschema = SchemaInterface(entry_point.python_package)
+for plugin in config.plugins.filtered_values():
+    if isinstance(plugin, Schema):
+        if plugin.name == 'simulationworkflowschema':
+            simulationworkflowschema = SchemaInterface(plugin.python_package)
+        elif plugin.name == 'runschema':
+            runschema = SchemaInterface(plugin.python_package)
         else:
-            importlib.import_module(entry_point.python_package)
+            importlib.import_module(plugin.python_package)
 
 SCHEMA_IMPORT_ERROR = 'Schema not defined.'
diff --git a/nomad/datamodel/metainfo/eln/__init__.py b/nomad/datamodel/metainfo/eln/__init__.py
index 29741b2c4bbd74884639eec8093a724d66131aad..1799f385464984ca4938a23535ba07d381121a54 100644
--- a/nomad/datamodel/metainfo/eln/__init__.py
+++ b/nomad/datamodel/metainfo/eln/__init__.py
@@ -1038,10 +1038,10 @@ class ElnWithStructureFile(ArchiveSection):
                 if system_normalizer_cls:
                     system_normalizer = system_normalizer_cls(archive)
                     system_normalizer.normalize()
-                optimade_normalizer = OptimadeNormalizer()
-                optimade_normalizer.normalize(archive)
-                results_normalizer = ResultsNormalizer()
-                results_normalizer.normalize(archive)
+                optimade_normalizer = OptimadeNormalizer(archive)
+                optimade_normalizer.normalize()
+                results_normalizer = ResultsNormalizer(archive)
+                results_normalizer.normalize()
 
         # TODO: rewrite it in a way in which the run section is not needed and System is
         # directly added to the archive.data
diff --git a/nomad/files.py b/nomad/files.py
index de4776bf1fed385536f8b5f0d56efae874662da5..7f1e8a2e8169784bf7709d8809bcf6b7d82c863e 100644
--- a/nomad/files.py
+++ b/nomad/files.py
@@ -1520,12 +1520,6 @@ class PublicUploadFiles(UploadFiles):
                 self._archive_msg_file_object = archive_msg_file_object
                 self._archive_hdf5_file_object = archive_hdf5_file_object
                 self._access = access
-
-                files_found = True
-                self._raw_zip_file_object = raw_zip_file_object
-                self._archive_msg_file_object = archive_msg_file_object
-                self._archive_hdf5_file_object = archive_hdf5_file_object
-                self._access = access
         if not files_found:
             raise KeyError('Neither public nor restricted files found')
         return self._access
diff --git a/nomad/metainfo/__init__.py b/nomad/metainfo/__init__.py
index 382c6e43cc1edcef3b624fcf6fad1a6cefe03645..be07523c0c4e3207e3085d9f4210291978d68199 100644
--- a/nomad/metainfo/__init__.py
+++ b/nomad/metainfo/__init__.py
@@ -42,7 +42,6 @@ from .metainfo import (
     Section,
     Category,
     Package,
-    SchemaPackage,
     Environment,
     MEnum,
     Datetime,
diff --git a/nomad/metainfo/elasticsearch_extension.py b/nomad/metainfo/elasticsearch_extension.py
index 422adb9d9cb08c26af30cdf50701d16ffe2874e9..a444a8db962cf890e0435d659474d54fe3010de0 100644
--- a/nomad/metainfo/elasticsearch_extension.py
+++ b/nomad/metainfo/elasticsearch_extension.py
@@ -177,7 +177,6 @@ from elasticsearch_dsl import Q
 
 from nomad import utils
 from nomad.config import config
-from nomad.config.models.plugins import Schema, Parser, SchemaPackageEntryPoint
 from nomad.metainfo.util import MTypes
 
 from .metainfo import (
@@ -502,27 +501,14 @@ class DocumentType:
 
         # Gather the list of enabled schema plugins. Raise error if duplicate
         # package name is encountered.
-        package_names = set()
-        packages_from_plugins = {}
-        for plugin in config.plugins.entry_points.filtered_values():
-            if isinstance(plugin, (Schema, Parser)):
-                package_name = plugin.python_package
-                if package_name in package_names:
+        packages = set()
+        for plugin in config.plugins.filtered_values():
+            if plugin.plugin_type in ['schema', 'parser']:
+                if plugin.python_package in packages:
                     raise ValueError(
                         f'Your plugin configuration contains two packages with the same name: {plugin.python_package}.'
                     )
-                package_names.add(package_name)
-            elif isinstance(plugin, SchemaPackageEntryPoint):
-                packages_from_plugins[plugin.id] = plugin.load()
-        for name, package in Package.registry.items():
-            if not name:
-                logger.warning(
-                    f'no name defined for package {package}, could not load dynamic quantities'
-                )
-                continue
-            package_name = name.split('.')[0]
-            if package_name in package_names:
-                packages_from_plugins[name] = package
+                packages.add(plugin.python_package)
 
         # Use to get all quantities from the given definition, TODO: Circular
         # definitions are here avoided by simply keeping track of which
@@ -550,21 +536,30 @@ class DocumentType:
                     yield item
 
         quantities_dynamic = {}
-        for package in packages_from_plugins.values():
-            for section in package.section_definitions:
-                if isinstance(section, Section) and issubclass(
-                    section.section_cls, EntryData
-                ):
-                    schema_name = section.qualified_name()
-                    for quantity_def, path, repeats in get_all_quantities(section):
-                        annotation = create_dynamic_quantity_annotation(quantity_def)
-                        if not annotation:
-                            continue
-                        full_name = f'data.{path}{schema_separator}{schema_name}'
-                        search_quantity = SearchQuantity(
-                            annotation, qualified_name=full_name, repeats=repeats
-                        )
-                        quantities_dynamic[full_name] = search_quantity
+        for name, package in Package.registry.items():
+            if not name:
+                logger.warning(
+                    f'no name defined for package {package}, could not load dynamic quantities'
+                )
+                continue
+            package_name = name.split('.')[0]
+            if package_name in packages:
+                for section in package.section_definitions:
+                    if isinstance(section, Section) and issubclass(
+                        section.section_cls, EntryData
+                    ):
+                        schema_name = section.qualified_name()
+                        for quantity_def, path, repeats in get_all_quantities(section):
+                            annotation = create_dynamic_quantity_annotation(
+                                quantity_def
+                            )
+                            if not annotation:
+                                continue
+                            full_name = f'data.{path}{schema_separator}{schema_name}'
+                            search_quantity = SearchQuantity(
+                                annotation, qualified_name=full_name, repeats=repeats
+                            )
+                            quantities_dynamic[full_name] = search_quantity
         self.quantities.update(quantities_dynamic)
 
     def _register(self, annotation, prefix, repeats):
diff --git a/nomad/metainfo/metainfo.py b/nomad/metainfo/metainfo.py
index ae8bcd2bd1ed92652ff045fa115548de0997ea01..3c666b307f9c0405ec5059b76a5b52fb92272f4f 100644
--- a/nomad/metainfo/metainfo.py
+++ b/nomad/metainfo/metainfo.py
@@ -5264,4 +5264,3 @@ class AnnotationModel(Annotation, BaseModel):
 
 
 AnnotationModel.update_forward_refs()
-SchemaPackage = Package
diff --git a/nomad/mkdocs.py b/nomad/mkdocs.py
index 52941dfdc7387f53fccb510a2edbe0f1b4540b9e..ee06a625d6f719464c8422ccb3b0fed1cc641503 100644
--- a/nomad/mkdocs.py
+++ b/nomad/mkdocs.py
@@ -33,7 +33,7 @@ from markdown.extensions.toc import slugify
 
 from nomad.utils import strip
 from nomad.config import config
-from nomad.config.models.plugins import Parser, EntryPointType
+from nomad.config.models.plugins import Parser, Plugin
 from nomad.app.v1.models import query_documentation, owner_documentation
 from nomad.app.v1.routers.entries import archive_required_documentation
 from nomad import utils
@@ -383,7 +383,7 @@ def define_env(env):
     def parser_list():  # pylint: disable=unused-variable
         parsers = [
             plugin
-            for _, plugin in config.plugins.entry_points.filtered_items()
+            for _, plugin in config.plugins.filtered_items()
             if isinstance(plugin, Parser)
         ]
 
@@ -446,21 +446,13 @@ def define_env(env):
 
     @env.macro
     def plugin_list():  # pylint: disable=unused-variable
-        plugins = [plugin for plugin in config.plugins.entry_points.options.values()]
+        plugins = [plugin for plugin in config.plugins.options.values()]
 
-        def render_plugin(plugin: EntryPointType) -> str:
+        def render_plugin(plugin: Plugin) -> str:
             result = plugin.name
-            docs_or_code_url = None
-            for field in [
-                'plugin_documentation_url',
-                'plugin_source_code_url',
-                'documentation',
-                'repository',
-            ]:
-                value = getattr(plugin, field, None)
-                if value:
-                    dosc_or_code_url = value
-                    break
+            docs_or_code_url = (
+                plugin.plugin_documentation_url or plugin.plugin_source_code_url
+            )
             if docs_or_code_url:
                 result = f'[{plugin.name}]({docs_or_code_url})'
             if plugin.description:
@@ -470,9 +462,7 @@ def define_env(env):
 
         categories = {}
         for plugin in plugins:
-            category = getattr(
-                plugin, 'plugin_type', getattr(plugin, 'entry_point_type', None)
-            )
+            category = plugin.python_package.split('.')[0]
             categories.setdefault(category, []).append(plugin)
 
         return '\n\n'.join(
diff --git a/nomad/normalizing/__init__.py b/nomad/normalizing/__init__.py
index 43da668aa0bd223abfcb9d78531ae78a1c4b5e3d..ec5c58b532584b045f0c59d87ce9c5a1b395ddcb 100644
--- a/nomad/normalizing/__init__.py
+++ b/nomad/normalizing/__init__.py
@@ -42,10 +42,7 @@ from collections import UserList
 
 from nomad.config import config
 
-from nomad.config.models.plugins import (
-    Normalizer as OldNormalizerPlugin,
-    NormalizerEntryPoint,
-)
+from nomad.config.models.plugins import Normalizer as NormalizerPlugin
 from .normalizer import Normalizer
 
 
@@ -67,7 +64,6 @@ class NormalizerInterface:
     def __init__(self, path: str) -> None:
         self._path = path
         self._cls = None
-        self.archive = None
 
     @property
     def normalizer_class(self):
@@ -76,49 +72,21 @@ class NormalizerInterface:
         return self._cls
 
     def normalize(self, logger=None):
-        self.normalizer.normalize(self.archive, logger)
+        self.normalizer_class.normalize(logger)
 
     def __call__(self, *args: Any) -> Any:
-        self.archive = args[0]
-        self.normalizer = self.normalizer_class(*args[1:])
-        return self
+        return self.normalizer_class(*args)
 
     def __getattr__(self, name: str):
         return getattr(self.normalizer_class, name, None)
 
 
-class NormalizerInterfaceNew:
-    def __init__(self, normalizer: Normalizer) -> None:
-        self.normalizer = normalizer
-        self.archive = None
-
-    def normalize(self, logger=None):
-        self.normalizer.normalize(self.archive, logger)
-
-    def __call__(self, *args: Any) -> Any:
-        self.archive = args[0]
-        return self
-
-    def __getattr__(self, name: str):
-        if name == '__name__':
-            return self.normalizer.__class__.__name__
-        return getattr(self.normalizer, name, None)
-
-
-config.load_plugins()
-enabled_entry_points = config.plugins.entry_points.filtered_values()
 normalizers = SortedNormalizers([])
 
-# Load normalizers using old plugin mechanism
-for entry_point in enabled_entry_points:
-    if isinstance(entry_point, OldNormalizerPlugin):
-        normalizers.append(NormalizerInterface(entry_point.normalizer_class_name))
 
-# Load normalizers using old config mechanism
+for plugin_name, plugin in config.plugins.options.items():
+    if isinstance(plugin, NormalizerPlugin) and config.plugins.filter(plugin_name):
+        normalizers.append(NormalizerInterface(plugin.normalizer_class_name))
+
 for normalizer in config.normalize.normalizers.filtered_values():
     normalizers.append(NormalizerInterface(normalizer))
-
-# Load normalizers using new plugin mechanism
-for entry_point in enabled_entry_points:
-    if isinstance(entry_point, NormalizerEntryPoint):
-        normalizers.append(NormalizerInterfaceNew(entry_point.load()))
diff --git a/nomad/normalizing/metainfo.py b/nomad/normalizing/metainfo.py
index 81fdf44b1fbbd54b09b4c86f35d914cae37b0758..7eefb5f9c84414be918875e54b672dd471e17256 100644
--- a/nomad/normalizing/metainfo.py
+++ b/nomad/normalizing/metainfo.py
@@ -16,17 +16,15 @@
 # limitations under the License.
 #
 
-from nomad.datamodel import EntryArchive
 from nomad.datamodel.data import ArchiveSection
-from nomad.datamodel import EntryArchive
-from typing import Optional
+from typing import List, Optional
 from . import Normalizer
 
 
 class MetainfoNormalizer(Normalizer):
     domain: Optional[str] = None
 
-    def normalize_section(self, archive: EntryArchive, section, logger):
+    def normalize_section(self, section, logger):
         normalize = None
         try:
             normalize = getattr(section, 'normalize')
@@ -35,7 +33,7 @@ class MetainfoNormalizer(Normalizer):
 
         if normalize:
             try:
-                normalize(archive, logger)
+                normalize(self.entry_archive, logger)
             except Exception as e:
                 logger.error(
                     'could not normalize section',
@@ -43,7 +41,7 @@ class MetainfoNormalizer(Normalizer):
                     exc_info=e,
                 )
 
-    def normalize(self, archive: EntryArchive, logger=None) -> None:
+    def normalize(self, logger=None) -> None:
         if logger is None:
             from nomad import utils
 
@@ -60,6 +58,6 @@ class MetainfoNormalizer(Normalizer):
             )
             for sub_section in sub_sections:
                 _normalize(sub_section)
-            self.normalize_section(archive, section, logger)
+            self.normalize_section(section, logger)
 
-        _normalize(archive)
+        _normalize(self.entry_archive)
diff --git a/nomad/normalizing/normalizer.py b/nomad/normalizing/normalizer.py
index 335249b45895fdd0bee82fccae7972a13820972f..145ec4db8e4ac00a7fecc0b64531bbd6f7d0caf5 100644
--- a/nomad/normalizing/normalizer.py
+++ b/nomad/normalizing/normalizer.py
@@ -26,10 +26,11 @@ from nomad.datamodel import EntryArchive
 
 class Normalizer(metaclass=ABCMeta):
     """
-    A base class for normalizers. Only one instance of the Normalizer is
-    created, and you should perform any heavy initialization in the constructor.
-    The normalize method is called on archives, and this function should ideally
-    not mutate the state of the shared normalizer instance.
+    A base class for normalizers. Normalizers work on a :class:`EntryArchive` section
+    for read and write. Normalizer instances are reused.
+
+    Arguments:
+        entry_archive: The entry_archive root section of the archive to normalize.
     """
 
     domain: Optional[str] = 'dft'
@@ -38,11 +39,16 @@ class Normalizer(metaclass=ABCMeta):
     """ Specifies the order of normalization with respect to other normalizers. Lower level
     is executed first."""
 
-    def __init__(self, **kwargs) -> None:
+    def __init__(self, entry_archive: EntryArchive) -> None:
+        self.entry_archive = entry_archive
+        try:
+            self.section_run = entry_archive.run[0]
+        except (AttributeError, IndexError):
+            self.section_run = None
         self.logger = get_logger(__name__)
 
     @abstractmethod
-    def normalize(self, archive: EntryArchive, logger=None) -> None:
+    def normalize(self, logger=None) -> None:
         if logger is not None:
             self.logger = logger.bind(normalizer=self.__class__.__name__)
 
@@ -59,8 +65,8 @@ class SystemBasedNormalizer(Normalizer, metaclass=ABCMeta):
         only_representatives: Will only normalize the `representative` systems.
     """
 
-    def __init__(self, only_representatives: bool = False, **kwargs):
-        super().__init__(**kwargs)
+    def __init__(self, entry_archive: EntryArchive, only_representatives: bool = False):
+        super().__init__(entry_archive)
         self.only_representatives = only_representatives
 
     @property
@@ -74,17 +80,15 @@ class SystemBasedNormalizer(Normalizer, metaclass=ABCMeta):
             'configuration_periodic_dimensions',
         ]
 
-    def _normalize_system(self, archive, system, is_representative):
-        return self.normalize_system(archive, system, is_representative)
+    def _normalize_system(self, system, is_representative):
+        return self.normalize_system(system, is_representative)
 
     @abstractmethod
-    def normalize_system(
-        self, archive: EntryArchive, system: MSection, is_representative: bool
-    ) -> bool:
-        """Normalize the given section and returns True, if successful"""
+    def normalize_system(self, system: MSection, is_representative: bool) -> bool:
+        """Normalize the given section and returns True, iff successful"""
         pass
 
-    def __representative_system(self, archive):
+    def __representative_system(self):
         """Used to select a representative system for this entry.
 
         Attempt to find a single section_system that is representative for the
@@ -95,7 +99,7 @@ class SystemBasedNormalizer(Normalizer, metaclass=ABCMeta):
 
         # Try to find workflow information and select the representative system
         # based on it
-        workflow = archive.workflow2
+        workflow = self.entry_archive.workflow2
 
         if workflow:
             try:
@@ -110,7 +114,7 @@ class SystemBasedNormalizer(Normalizer, metaclass=ABCMeta):
         # available in reverse order until a valid one is found.
         if system is None:
             try:
-                sccs = archive.run[0].calculation
+                sccs = self.section_run.calculation
                 for iscc in reversed(sccs):
                     isys = iscc.system_ref
                     if isys is not None:
@@ -123,7 +127,7 @@ class SystemBasedNormalizer(Normalizer, metaclass=ABCMeta):
             # If no sccs exist, try to find systems
             if system is None:
                 try:
-                    system = archive.run[0].system[-1]
+                    system = self.section_run.system[-1]
                 except Exception:
                     system = None
 
@@ -142,17 +146,17 @@ class SystemBasedNormalizer(Normalizer, metaclass=ABCMeta):
                 pass
 
         if scc is not None:
-            archive.run[0].m_cache['representative_scc_idx'] = scc.m_parent_index
+            self.section_run.m_cache['representative_scc_idx'] = scc.m_parent_index
         if system is not None:
-            archive.run[0].m_cache['representative_system_idx'] = system.m_parent_index
+            self.section_run.m_cache['representative_system_idx'] = (
+                system.m_parent_index
+            )
 
         return system.m_resolved() if system is not None else None
 
-    def __normalize_system(
-        self, archive: EntryArchive, system, representative, logger=None
-    ) -> bool:
+    def __normalize_system(self, system, representative, logger=None) -> bool:
         try:
-            return self._normalize_system(archive, system, representative)
+            return self._normalize_system(system, representative)
 
         except KeyError as e:
             self.logger.error(
@@ -176,22 +180,22 @@ class SystemBasedNormalizer(Normalizer, metaclass=ABCMeta):
             )
             raise e
 
-    def normalize(self, archive: EntryArchive, logger=None) -> None:
-        super().normalize(archive, logger)
+    def normalize(self, logger=None) -> None:
+        super().normalize(logger)
         # If no section run detected, do nothing
-        if not archive.run:
+        if self.section_run is None:
             return
 
         # Process representative system first
         repr_sys_idx = None
-        repr_sys = self.__representative_system(archive)
+        repr_sys = self.__representative_system()
         if repr_sys is not None:
             repr_sys_idx = repr_sys.m_parent_index
             self.logger.info('chose "representative" section system')
-            self.__normalize_system(archive, repr_sys, True, logger)
+            self.__normalize_system(repr_sys, True, logger)
 
         # All the rest if requested
         if not self.only_representatives:
-            for isys, system in enumerate(archive.run[0].system):
+            for isys, system in enumerate(self.section_run.system):
                 if isys != repr_sys_idx:
-                    self.__normalize_system(archive, system, False, logger)
+                    self.__normalize_system(system, False, logger)
diff --git a/nomad/normalizing/optimade.py b/nomad/normalizing/optimade.py
index c8f4ea6bc19c826e8a2dd4abfc675fcdeb740c9c..77db87723b3570041bc15c53121a6c15f0f9d218 100644
--- a/nomad/normalizing/optimade.py
+++ b/nomad/normalizing/optimade.py
@@ -23,7 +23,6 @@ import ase.data
 import ase.formula
 import pint.quantity
 
-from nomad.datamodel import EntryArchive
 from nomad.atomutils import Formula
 from nomad.normalizing.normalizer import SystemBasedNormalizer
 from nomad.units import ureg
@@ -89,18 +88,18 @@ class OptimadeNormalizer(SystemBasedNormalizer):
     It assumes that the :class:`SystemNormalizer` was run before.
     """
 
-    def __init__(self):
-        super().__init__(only_representatives=True)
+    def __init__(self, archive):
+        super().__init__(archive, only_representatives=True)
 
-    def add_optimade_data(self, archive: EntryArchive) -> OptimadeEntry:
+    def add_optimade_data(self, index) -> OptimadeEntry:
         """
         The 'main' method of this :class:`SystemBasedNormalizer`.
         Normalizes the section with the given `index`.
         Normalizes geometry, classifies, system_type, and runs symmetry analysis.
         """
-        if archive.metadata is None:
-            archive.m_create(EntryMetadata)
-        optimade = archive.metadata.m_create(OptimadeEntry)
+        if self.entry_archive.metadata is None:
+            self.entry_archive.m_create(EntryMetadata)
+        optimade = self.entry_archive.metadata.m_create(OptimadeEntry)
 
         def get_value(
             quantity_def,
@@ -110,7 +109,7 @@ class OptimadeNormalizer(SystemBasedNormalizer):
             source: Any = None,
         ) -> Any:
             try:
-                source = source if source is not None else archive.run[0].system[-1]
+                source = source if source is not None else self.section_run.system[-1]
                 value = source.m_get(quantity_def)
                 if value is None:
                     return
@@ -129,7 +128,7 @@ class OptimadeNormalizer(SystemBasedNormalizer):
             except KeyError:
                 return default
 
-        system = archive.run[0].system[-1] if archive.run[0].system else None
+        system = self.section_run.system[-1] if self.section_run.system else None
         if system is None:
             return optimade
 
@@ -154,9 +153,9 @@ class OptimadeNormalizer(SystemBasedNormalizer):
         ]
 
         # formulas
-        system_cls = (
-            archive.run[0].m_def.all_sub_sections['system'].sub_section.section_cls
-        )
+        system_cls = self.section_run.m_def.all_sub_sections[
+            'system'
+        ].sub_section.section_cls
         original_formula = get_value(
             system_cls.chemical_composition_hill, source=system
         )
@@ -199,12 +198,12 @@ class OptimadeNormalizer(SystemBasedNormalizer):
 
         return optimade
 
-    def normalize_system(self, archive: EntryArchive, system, is_representative):
+    def normalize_system(self, system, is_representative):
         if not is_representative:
             return False
 
         try:
-            self.add_optimade_data(archive)
+            self.add_optimade_data(system.m_parent_index)
             return True
 
         except Exception as e:
diff --git a/nomad/normalizing/porosity.py b/nomad/normalizing/porosity.py
index d780765f54f4e4951c7ac4227face50fb0caa69b..17ea50d7dcb6fc528f404d8f7b990d222a0dbd1e 100644
--- a/nomad/normalizing/porosity.py
+++ b/nomad/normalizing/porosity.py
@@ -63,8 +63,8 @@ class PorosityNormalizer(SystemBasedNormalizer):
     In the future, the it will also compute the rcsr tological code.
     """
 
-    def __init__(self):
-        super().__init__(only_representatives=True)
+    def __init__(self, archive):
+        super().__init__(archive, only_representatives=True)
 
     def normalize_system(self, system, is_representative):
         if not is_representative:
diff --git a/nomad/normalizing/results.py b/nomad/normalizing/results.py
index edb0ac873cb93a9c3621e938928093009721f7fc..936e91583415e24f4ea425956e7581384e460598 100644
--- a/nomad/normalizing/results.py
+++ b/nomad/normalizing/results.py
@@ -30,7 +30,6 @@ from nomad.atomutils import Formula
 from nomad.normalizing.normalizer import Normalizer
 from nomad.normalizing.method import MethodNormalizer
 from nomad.normalizing.material import MaterialNormalizer
-from nomad.datamodel import EntryArchive
 from nomad.datamodel.metainfo.workflow import Workflow
 from nomad.datamodel.data import ArchiveSection
 from nomad.normalizing.common import structures_2d
@@ -103,10 +102,7 @@ class ResultsNormalizer(Normalizer):
     domain = None
     normalizer_level = 3
 
-    def normalize(self, archive: EntryArchive, logger=None) -> None:
-        self.entry_archive = archive
-        self.section_run = archive.run[0] if archive.run else None
-
+    def normalize(self, logger=None) -> None:
         # Setup logger
         if logger is not None:
             self.logger = logger.bind(normalizer=self.__class__.__name__)
@@ -123,9 +119,6 @@ class ResultsNormalizer(Normalizer):
         for measurement in self.entry_archive.measurement:
             self.normalize_measurement(measurement)
 
-        self.entry_archive = None
-        self.section_run = None
-
     def normalize_sample(self, sample) -> None:
         material = self.entry_archive.m_setdefault('results.material')
 
diff --git a/nomad/normalizing/topology.py b/nomad/normalizing/topology.py
index a2a7bf774c1d1cb7e7d699ab2f1c159bfce47dfd..00415768d94c996eff10e013405d2b234baa73fb 100644
--- a/nomad/normalizing/topology.py
+++ b/nomad/normalizing/topology.py
@@ -40,6 +40,7 @@ from matid.classification.classifications import (
 from nomad import utils
 from nomad.config import config
 from nomad import atomutils
+from nomad.units import ureg
 from nomad.datamodel.results import (
     CoreHole,
     SymmetryNew as Symmetry,
diff --git a/nomad/parsing/parser.py b/nomad/parsing/parser.py
index 38b671ed2fe40ceab424898aa8e017a8683de06c..513ae79202c8c8bbfea713204c30404d94743d7f 100644
--- a/nomad/parsing/parser.py
+++ b/nomad/parsing/parser.py
@@ -216,7 +216,6 @@ class MatchingParser(Parser):
         domain='dft',
         metadata: dict = None,
         supported_compressions: List[str] = [],
-        **kwargs,
     ) -> None:
         super().__init__()
 
diff --git a/nomad/parsing/parsers.py b/nomad/parsing/parsers.py
index 8b5aa9836fa28854d1ffe9e4bbbd78fdff3d5865..c35340e39884964775b480382e4c434e482068ee 100644
--- a/nomad/parsing/parsers.py
+++ b/nomad/parsing/parsers.py
@@ -21,7 +21,7 @@ from typing import Optional, Tuple, List, Dict
 from collections.abc import Iterable
 
 from nomad.config import config
-from nomad.config.models.plugins import Parser as ParserPlugin, ParserEntryPoint
+from nomad.config.models.plugins import Parser as ParserPlugin
 from nomad.datamodel import EntryArchive, EntryMetadata, results
 from nomad.datamodel.context import Context, ClientContext
 
@@ -226,27 +226,13 @@ def run_parser(
 
 
 parsers = [GenerateRandomParser(), TemplateParser(), ChaosParser()]
-config.load_plugins()
-enabled_entry_points = config.plugins.entry_points.filtered_values()
-
-# Load parsers using old plugin mechanism
 parsers.extend(
     [
-        entry_point.create_matching_parser_interface()
-        for entry_point in enabled_entry_points
-        if isinstance(entry_point, ParserPlugin)
+        plugin.create_matching_parser_interface()
+        for plugin_name, plugin in config.plugins.options.items()
+        if config.plugins.filter(plugin_name) and isinstance(plugin, ParserPlugin)
     ]
 )
-
-# Load parsers using new plugin mechanism. The entry point name is used to
-# identify the parser.
-for entry_point in enabled_entry_points:
-    if isinstance(entry_point, ParserEntryPoint):
-        entry_point_name = entry_point.id
-        instance = entry_point.load()
-        instance.name = entry_point_name
-        parsers.append(instance)
-
 parsers.extend([TabularDataParser(), ArchiveParser()])
 
 # There are some entries with PIDs that have mainfiles which do not match what
@@ -284,10 +270,12 @@ if config.process.use_empty_parsers:
 
 parsers.append(BrokenParser())
 
-""" A dict to access parsers by name. Usually 'parsers/<...>', e.g. 'parsers/vasp'. """
+
 parser_dict: Dict[str, Parser] = {
     parser.name: parser for parser in parsers + empty_parsers
-}
+}  # type: ignore
+""" A dict to access parsers by name. Usually 'parsers/<...>', e.g. 'parsers/vasp'. """
+
 
 # renamed parsers
 _renames = {
diff --git a/pyproject.toml b/pyproject.toml
index 354fbda9a494669a75a7434bef5b5f3bcfa2213f..c21d95504eb7d1f6e50b53c0a96fa307e8e36406 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,7 +24,6 @@ dependencies = [
     'h5py>=3.6.0',
     'hjson>=3.0.2',
     'httpx>=0.23.3',
-    'importlib_metadata~=7.1.0',
     'jmespath>=0.10.0',
     'lxml>=5.2',
     'lxml-html-clean>=0.1.0',
diff --git a/requirements-dev.txt b/requirements-dev.txt
index 96429ce7f84175ebdf3276c49fb6bec8d509844e..b6d4a8611c4ed0ccbd38dd381b1042d04eeda9d9 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -22,7 +22,7 @@ async-generator==1.10     # via -r requirements.txt, jupyterhub
 atpublic==4.1.0           # via aiosmtpd
 attrs==23.2.0             # via -r requirements.txt, aiosmtpd, jsonschema, pytest
 babel==2.14.0             # via -r requirements.txt, mkdocs-git-revision-date-localized-plugin, mkdocs-material, sphinx
-backports-tarfile==1.1.0  # via jaraco-context
+backports-tarfile==1.0.0  # via jaraco-context
 bagit==1.8.1              # via -r requirements.txt, nomad-lab (pyproject.toml)
 basicauth==0.4.1          # via -r requirements.txt, nomad-lab (pyproject.toml)
 beautifulsoup4==4.12.3    # via -r requirements.txt, nomad-lab (pyproject.toml)
@@ -33,7 +33,7 @@ blinker==1.7.0            # via -r requirements.txt, flask
 blosc2==2.5.1             # via -r requirements.txt, tables
 build==1.2.1              # via nomad-lab (pyproject.toml), pip-tools
 cachetools==5.3.3         # via -r requirements.txt, nomad-lab (pyproject.toml)
-celery==5.4.0             # via -r requirements.txt, nomad-lab (pyproject.toml)
+celery==5.3.6             # via -r requirements.txt, nomad-lab (pyproject.toml)
 certifi==2024.2.2         # via -r requirements.txt, elasticsearch, httpcore, httpx, requests
 certipy==0.1.3            # via -r requirements.txt, jupyterhub
 cffi==1.16.0              # via -r requirements.txt, cryptography
@@ -63,7 +63,7 @@ dnspython==2.6.1          # via -r requirements.txt, email-validator, pymongo
 docker==7.0.0             # via -r requirements.txt, dockerspawner
 dockerspawner==13.0.0     # via -r requirements.txt, nomad-lab (pyproject.toml)
 docstring-parser==0.16    # via -r requirements.txt, nomad-lab (pyproject.toml)
-docutils==0.21.1          # via -r requirements.txt, m2r, readme-renderer, recommonmark, sphinx
+docutils==0.20.1          # via -r requirements.txt, m2r, readme-renderer, recommonmark, sphinx
 elasticsearch==7.17.1     # via -r requirements.txt, elasticsearch-dsl, nomad-lab (pyproject.toml)
 elasticsearch-dsl==7.4.0  # via -r requirements.txt, nomad-lab (pyproject.toml)
 email-validator==1.3.1    # via -r requirements.txt, optimade
@@ -107,7 +107,7 @@ idna==3.7                 # via -r requirements.txt, anyio, email-validator, htt
 ifes-apt-tc-data-modeling==0.1  # via -r requirements.txt, pynxtools
 imageio==2.27.0           # via -r requirements.txt, hyperspy, kikuchipy, nionswift, nionswift-io, nionui, scikit-image
 imagesize==1.4.1          # via -r requirements.txt, sphinx
-importlib-metadata==7.1.0  # via -r requirements.txt, build, dask, flask, hyperspy, jupyter-client, jupyterhub, keyring, markdown, mkdocs, nomad-lab (pyproject.toml), pynxtools, sphinx, twine
+importlib-metadata==7.1.0  # via -r requirements.txt, build, dask, flask, hyperspy, jupyter-client, jupyterhub, keyring, markdown, mkdocs, pynxtools, sphinx, twine
 importlib-resources==6.4.0  # via -r requirements.txt, matplotlib, spglib
 inflection==0.5.1         # via -r requirements.txt, nomad-lab (pyproject.toml)
 ipykernel==6.29.4         # via -r requirements.txt, ipyparallel
@@ -115,7 +115,7 @@ ipyparallel==8.8.0        # via -r requirements.txt, hyperspy
 ipython==8.18.1           # via -r requirements.txt, hyperspy, ipykernel, ipyparallel, pynxtools-stm
 isodate==0.6.1            # via -r requirements.txt, rdflib
 isoduration==20.11.0      # via -r requirements.txt, jsonschema
-itsdangerous==2.2.0       # via -r requirements.txt, flask, nomad-lab (pyproject.toml)
+itsdangerous==2.1.2       # via -r requirements.txt, flask, nomad-lab (pyproject.toml)
 jaraco-classes==3.4.0     # via keyring
 jaraco-context==5.3.0     # via keyring
 jaraco-functools==4.0.0   # via keyring
@@ -165,7 +165,7 @@ mkdocs-redirects==1.2.1   # via nomad-lab (pyproject.toml)
 mmtf-python==1.1.3        # via -r requirements.txt, mdanalysis
 mongoengine==0.28.2       # via -r requirements.txt, nomad-lab (pyproject.toml)
 mongomock==4.1.2          # via -r requirements.txt, optimade
-monty==2024.4.17          # via -r requirements.txt, pymatgen
+monty==2024.3.31          # via -r requirements.txt, pymatgen
 more-itertools==10.2.0    # via jaraco-classes, jaraco-functools, pytest
 mpmath==1.3.0             # via -r requirements.txt, sympy
 mrcfile==1.5.0            # via -r requirements.txt, griddataformats
@@ -213,7 +213,7 @@ pint==0.17                # via -r requirements.txt, hyperspy, nomad-lab (pyproj
 pip-tools==7.4.1          # via nomad-lab (pyproject.toml)
 pkginfo==1.10.0           # via twine
 platformdirs==4.2.0       # via -r requirements.txt, jupyter-core, mkdocs, pooch
-plotly==5.21.0            # via -r requirements.txt, asr, pymatgen
+plotly==5.20.0            # via -r requirements.txt, asr, pymatgen
 pluggy==0.13.1            # via pytest
 pooch==1.8.1              # via -r requirements.txt, kikuchipy, orix
 prettytable==3.10.0       # via -r requirements.txt, hyperspy
@@ -274,7 +274,7 @@ rdflib==5.0.0             # via -r requirements.txt, nomad-lab (pyproject.toml)
 rdkit==2023.9.5           # via -r requirements.txt, nomad-lab (pyproject.toml)
 readme-renderer==43.0     # via twine
 recommonmark==0.7.1       # via -r requirements.txt, nomad-lab (pyproject.toml)
-regex==2024.4.16          # via mkdocs-material
+regex==2023.12.25         # via mkdocs-material
 requests==2.31.0          # via -r requirements.txt, docker, hyperspy, jupyterhub, mkdocs-material, nomad-lab (pyproject.toml), oauthenticator, optimade, pooch, pybis, pymatgen, python-gitlab, python-keycloak, requests-toolbelt, rfc3161ng, sphinx, twine
 requests-toolbelt==1.0.0  # via -r requirements.txt, python-gitlab, python-keycloak, twine
 rfc3161ng==2.1.3          # via -r requirements.txt, nomad-lab (pyproject.toml)
@@ -299,7 +299,7 @@ snowballstemmer==2.2.0    # via -r requirements.txt, sphinx
 soupsieve==2.5            # via -r requirements.txt, beautifulsoup4
 sparse==0.15.1            # via -r requirements.txt, hyperspy
 spglib==2.4.0             # via -r requirements.txt, asr, matid, phonopy, pymatgen
-sphinx==7.3.6             # via -r requirements.txt, recommonmark
+sphinx==7.2.6             # via -r requirements.txt, recommonmark
 sphinxcontrib-applehelp==1.0.8  # via -r requirements.txt, sphinx
 sphinxcontrib-devhelp==1.0.6  # via -r requirements.txt, sphinx
 sphinxcontrib-htmlhelp==2.0.5  # via -r requirements.txt, sphinx
@@ -317,8 +317,8 @@ tenacity==8.2.3           # via -r requirements.txt, plotly
 termcolor==2.4.0          # via mkdocs-macros-plugin
 texttable==1.7.0          # via -r requirements.txt, pybis
 threadpoolctl==3.4.0      # via -r requirements.txt, mdanalysis, scikit-learn
-tifffile==2024.4.18       # via -r requirements.txt, h5grove, hyperspy, scikit-image
-tomli==2.0.1              # via -r requirements.txt, build, mypy, pip-tools, pyproject-hooks, sphinx
+tifffile==2024.2.12       # via -r requirements.txt, h5grove, hyperspy, scikit-image
+tomli==2.0.1              # via build, mypy, pip-tools, pyproject-hooks
 toolz==0.12.1             # via -r requirements.txt, dask, hyperspy, partd
 toposort==1.10            # via -r requirements.txt, nomad-lab (pyproject.toml)
 tornado==6.4              # via -r requirements.txt, ipykernel, ipyparallel, jupyter-client, jupyterhub
diff --git a/requirements.txt b/requirements.txt
index 189c613473a61272643a7bb6fd134d79375f42f0..f5ab4edbc8f85682b94777d8227bad6876635918 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -28,7 +28,7 @@ bitarray==2.9.2           # via nomad-lab (pyproject.toml), nomad_dos_fingerprin
 blinker==1.7.0            # via flask
 blosc2==2.5.1             # via tables
 cachetools==5.3.3         # via nomad-lab (pyproject.toml)
-celery==5.4.0             # via nomad-lab (pyproject.toml)
+celery==5.3.6             # via nomad-lab (pyproject.toml)
 certifi==2024.2.2         # via elasticsearch, httpcore, httpx, requests
 certipy==0.1.3            # via jupyterhub
 cffi==1.16.0              # via cryptography
@@ -55,7 +55,7 @@ dnspython==2.6.1          # via email-validator, pymongo
 docker==7.0.0             # via dockerspawner
 dockerspawner==13.0.0     # via nomad-lab (pyproject.toml)
 docstring-parser==0.16    # via nomad-lab (pyproject.toml)
-docutils==0.21.1          # via m2r, recommonmark, sphinx
+docutils==0.20.1          # via m2r, recommonmark, sphinx
 elasticsearch==7.17.1     # via elasticsearch-dsl, nomad-lab (pyproject.toml)
 elasticsearch-dsl==7.4.0  # via nomad-lab (pyproject.toml)
 email-validator==1.3.1    # via optimade
@@ -96,7 +96,7 @@ idna==3.7                 # via anyio, email-validator, httpx, jsonschema, reque
 ifes-apt-tc-data-modeling==0.1  # via pynxtools
 imageio==2.27.0           # via hyperspy, kikuchipy, nionswift, nionswift-io, nionui, scikit-image
 imagesize==1.4.1          # via sphinx
-importlib-metadata==7.1.0  # via dask, flask, hyperspy, jupyter-client, jupyterhub, nomad-lab (pyproject.toml), pynxtools, sphinx
+importlib-metadata==7.1.0  # via dask, flask, hyperspy, jupyter-client, jupyterhub, pynxtools, sphinx
 importlib-resources==6.4.0  # via matplotlib, spglib
 inflection==0.5.1         # via nomad-lab (pyproject.toml)
 ipykernel==6.29.4         # via ipyparallel
@@ -104,7 +104,7 @@ ipyparallel==8.8.0        # via hyperspy
 ipython==8.18.1           # via hyperspy, ipykernel, ipyparallel, pynxtools-stm
 isodate==0.6.1            # via rdflib
 isoduration==20.11.0      # via jsonschema
-itsdangerous==2.2.0       # via flask, nomad-lab (pyproject.toml)
+itsdangerous==2.1.2       # via flask, nomad-lab (pyproject.toml)
 jedi==0.19.1              # via ipython
 jinja2==3.1.3             # via flask, hyperspy, jupyterhub, sphinx
 jmespath==1.0.1           # via nomad-lab (pyproject.toml)
@@ -140,7 +140,7 @@ mistune==3.0.2            # via m2r
 mmtf-python==1.1.3        # via mdanalysis
 mongoengine==0.28.2       # via nomad-lab (pyproject.toml)
 mongomock==4.1.2          # via optimade
-monty==2024.4.17          # via pymatgen
+monty==2024.3.31          # via pymatgen
 mpmath==1.3.0             # via sympy
 mrcfile==1.5.0            # via griddataformats
 msgpack==1.0.8            # via blosc2, mmtf-python, nomad-lab (pyproject.toml)
@@ -179,7 +179,7 @@ phonopy==2.9.1            # via asr
 pillow==10.0.1            # via fabio, hyperspy, imageio, matplotlib, nionswift, rdkit, scikit-image
 pint==0.17                # via hyperspy, nomad-lab (pyproject.toml), rosettasciio
 platformdirs==4.2.0       # via jupyter-core, pooch
-plotly==5.21.0            # via asr, pymatgen
+plotly==5.20.0            # via asr, pymatgen
 pooch==1.8.1              # via hyperspy, kikuchipy, orix
 prettytable==3.10.0       # via hyperspy
 prometheus-client==0.20.0  # via jupyterhub
@@ -247,7 +247,7 @@ snowballstemmer==2.2.0    # via sphinx
 soupsieve==2.5            # via beautifulsoup4
 sparse==0.15.1            # via hyperspy
 spglib==2.4.0             # via asr, matid, phonopy, pymatgen
-sphinx==7.3.6             # via recommonmark
+sphinx==7.2.6             # via recommonmark
 sphinxcontrib-applehelp==1.0.8  # via sphinx
 sphinxcontrib-devhelp==1.0.6  # via sphinx
 sphinxcontrib-htmlhelp==2.0.5  # via sphinx
@@ -264,8 +264,7 @@ tabulate==0.8.9           # via nomad-lab (pyproject.toml), pybis, pymatgen
 tenacity==8.2.3           # via plotly
 texttable==1.7.0          # via pybis
 threadpoolctl==3.4.0      # via mdanalysis, scikit-learn
-tifffile==2024.4.18       # via h5grove, hyperspy, scikit-image
-tomli==2.0.1              # via sphinx
+tifffile==2024.2.12       # via h5grove, hyperspy, scikit-image
 toolz==0.12.1             # via dask, hyperspy, partd
 toposort==1.10            # via nomad-lab (pyproject.toml)
 tornado==6.4              # via ipykernel, ipyparallel, jupyter-client, jupyterhub
diff --git a/tests/normalizing/conftest.py b/tests/normalizing/conftest.py
index b6ae32ecdd060cc539a3594f815f470b504c1646..8f5df250fcd8c39f4d6a45fb3a4cc0b668afef86 100644
--- a/tests/normalizing/conftest.py
+++ b/tests/normalizing/conftest.py
@@ -71,7 +71,7 @@ from nomad.datamodel.metainfo import (
 def run_normalize(entry_archive: EntryArchive) -> EntryArchive:
     for normalizer_class in normalizers:
         normalizer = normalizer_class(entry_archive)
-        normalizer.normalize(logger=get_logger(__name__))
+        normalizer.normalize()
     return entry_archive
 
 
diff --git a/tests/test_config.py b/tests/test_config.py
index b4482e742b47166f718a9adb8d76ae2fb17cd65d..ef167f2bd93a9391ce140ca39d8ebd0189e51f5e 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -173,20 +173,18 @@ def test_config_priority(conf_yaml, conf_env, value, mockopen, monkeypatch):
             {'plugins': {'include': ['normalizers/simulation/dos']}},
             {
                 'plugins': {
-                    'entry_points': {
-                        'include': ['normalizers/simulation/dos'],
-                        'options': {
-                            'normalizers/simulation/dos': {
-                                'name': 'yaml',
-                                'python_package': 'dosnormalizer',
-                                'description': 'This is the normalizer for DOS in NOMAD.\n',
-                                'plugin_documentation_url': None,
-                                'plugin_source_code_url': None,
-                                'normalizer_class_name': 'dosnormalizer.DosNormalizer',
-                                'plugin_type': 'normalizer',
-                            }
-                        },
-                    }
+                    'include': ['normalizers/simulation/dos'],
+                    'options': {
+                        'normalizers/simulation/dos': {
+                            'name': 'yaml',
+                            'python_package': 'dosnormalizer',
+                            'description': 'This is the normalizer for DOS in NOMAD.\n',
+                            'plugin_documentation_url': None,
+                            'plugin_source_code_url': None,
+                            'normalizer_class_name': 'dosnormalizer.DosNormalizer',
+                            'plugin_type': 'normalizer',
+                        }
+                    },
                 }
             },
             id='dictionary: merges',
@@ -194,7 +192,7 @@ def test_config_priority(conf_yaml, conf_env, value, mockopen, monkeypatch):
         pytest.param(
             {'plugins': {'include': ['a']}},
             {'plugins': {'include': ['b']}},
-            {'plugins': {'entry_points': {'include': ['b']}}},
+            {'plugins': {'include': ['b']}},
             id='list: overrides',
         ),
         pytest.param(
@@ -219,9 +217,9 @@ def test_parser_plugins():
     config = load_config()
     config.load_plugins()
     parsers = [
-        entry_point
-        for entry_point in config.plugins.entry_points.options.values()
-        if isinstance(entry_point, Parser)
+        plugin
+        for plugin in config.plugins.options.values()
+        if isinstance(plugin, Parser)
     ]
     assert len(parsers) == 71
 
@@ -246,5 +244,5 @@ def test_plugin_polymorphism(mockopen, monkeypatch):
     }
     config = load_test_config(plugins, None, mockopen, monkeypatch)
     config.load_plugins()
-    assert isinstance(config.plugins.entry_points.options['schema'], Schema)
-    assert isinstance(config.plugins.entry_points.options['parser'], Parser)
+    assert isinstance(config.plugins.options['schema'], Schema)
+    assert isinstance(config.plugins.options['parser'], Parser)