diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index eada9cdb1735089098109dd633a3fd30f5a0fdea..5fba23531559515d75d87cf120d1c69287782823 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -9,6 +9,7 @@
 </template>
 
 <script>
+import {UI} from '@/store/modules/ui'
 import AutoLogout from '@/components/AutoLogout'
 
 export default {
@@ -16,7 +17,7 @@ export default {
   name: 'app',
   computed: {
     darkMode () {
-      return this.$store.state.ui.darkMode
+      return UI.state.darkMode
     }
   }
 }
diff --git a/frontend/src/components/BaseLayout.vue b/frontend/src/components/BaseLayout.vue
index 87a1485174e18ffbc677a134398a15598d774210..b02083b3b0c8423a6270fc8309d920fff25d4cc6 100644
--- a/frontend/src/components/BaseLayout.vue
+++ b/frontend/src/components/BaseLayout.vue
@@ -85,7 +85,7 @@
 
 <script>
 import { mapGetters, mapState } from 'vuex'
-import {uiMut} from '@/store/modules/ui'
+import {UI} from '@/store/modules/ui'
 import { mapStateToComputedGetterSetter } from '@/util/helpers'
 import UserOptions from '@/components/UserOptions'
 
@@ -101,20 +101,20 @@ export default {
       userRole: state => state.authentication.user.role
     }),
     ...mapStateToComputedGetterSetter({
-      pathPrefix: 'ui',
+      pathPrefix: 'UI',
       items: [
         {
           name: 'darkMode',
-          mutation: uiMut.SET_DARK_MODE
+          mutation: UI.SET_DARK_MODE
         },
         {
           name: 'darkModeUnlocked',
-          mutation: uiMut.SET_DARK_MODE_UNLOCKED
+          mutation: UI.SET_DARK_MODE_UNLOCKED
         },
         {
           name: 'mini',
           path: 'sideBarCollapsed',
-          mutation: uiMut.SET_SIDEBAR_COLLAPSED
+          mutation: UI.SET_SIDEBAR_COLLAPSED
         }
       ]
     }),
diff --git a/frontend/src/components/SubmissionType.vue b/frontend/src/components/SubmissionType.vue
index 253ebad3794f388ef37b34eba0d99673d90f2713..65f694bd08a8db6a027e6443427555abca458925 100644
--- a/frontend/src/components/SubmissionType.vue
+++ b/frontend/src/components/SubmissionType.vue
@@ -32,8 +32,9 @@
 </template>
 
 <script>
-import {mapState} from 'vuex'
 import {highlight} from 'highlight.js'
+import {UI} from '@/store/modules/ui'
+
 export default {
   name: 'submission-type',
   props: {
@@ -72,9 +73,6 @@ export default {
     }
   },
   computed: {
-    ...mapState({
-      darkMode: state => state.ui.darkMode
-    }),
     typeItems () {
       let items = [
         {
@@ -96,7 +94,7 @@ export default {
       return highlight(this.programmingLanguage, this.solution, true).value
     },
     backgroundColor () {
-      return this.darkMode ? 'grey' : '#F3F3F3'
+      return UI.state.darkMode ? 'grey' : '#F3F3F3'
     }
   }
 }
diff --git a/frontend/src/components/submission_notes/base/FeedbackComment.vue b/frontend/src/components/submission_notes/base/FeedbackComment.vue
index 989689e6f2fe3cc4e7a9e7d13c27355ccdbe2b4d..29dd835708ecd5e1d01e5bb39b822e4eb327d0e6 100644
--- a/frontend/src/components/submission_notes/base/FeedbackComment.vue
+++ b/frontend/src/components/submission_notes/base/FeedbackComment.vue
@@ -37,6 +37,7 @@
 
 <script>
 import {mapState} from 'vuex'
+import {UI} from '@/store/modules/ui'
 import {subNotesMut, subNotesNamespace} from '@/store/modules/submission-notes'
 
 export default {
@@ -77,8 +78,7 @@ export default {
   },
   computed: {
     ...mapState({
-      markedForDeletion: state => state.submissionNotes.commentsMarkedForDeletion,
-      darkMode: state => state.ui.darkMode
+      markedForDeletion: state => state.submissionNotes.commentsMarkedForDeletion
     }),
     parsedCreated () {
       if (this.created) {
@@ -94,7 +94,7 @@ export default {
       return 'orange'
     },
     backgroundColor () {
-      return this.darkMode ? 'grey' : '#F3F3F3'
+      return UI.state.darkMode ? 'grey' : '#F3F3F3'
     }
   },
   methods: {
diff --git a/frontend/src/components/subscriptions/SubscriptionList.vue b/frontend/src/components/subscriptions/SubscriptionList.vue
index 2e8b7f72b1a704b90fea1c8bd582e3bd2aa0b371..d62b05a93266d1e036fc6646cfda881966ff1aa1 100644
--- a/frontend/src/components/subscriptions/SubscriptionList.vue
+++ b/frontend/src/components/subscriptions/SubscriptionList.vue
@@ -29,6 +29,7 @@
 
 <script>
 import {mapGetters, mapActions, mapState} from 'vuex'
+import {UI} from '@/store/modules/ui'
 import SubscriptionCreation from '@/components/subscriptions/SubscriptionCreation'
 import SubscriptionForList from '@/components/subscriptions/SubscriptionForList'
 import SubscriptionsForStage from '@/components/subscriptions/SubscriptionsForStage'
@@ -52,16 +53,13 @@ export default {
     }
   },
   computed: {
-    ...mapState({
-      sideBarCollapsed: state => state.ui.sideBarCollapsed
-    }),
     ...mapGetters({
       subscriptions: 'getSubscriptionsGroupedByType',
       stages: 'availableStages',
       stagesReadable: 'availableStagesReadable'
     }),
     showDetail () {
-      return !this.sidebar || (this.sidebar && !this.sideBarCollapsed)
+      return !this.sidebar || (this.sidebar && !UI.state.sideBarCollapsed)
     }
   },
   methods: {
diff --git a/frontend/src/pages/student/StudentLayout.vue b/frontend/src/pages/student/StudentLayout.vue
index f8bc7d5b0187d9f2f44191ceebed6642ecca9b34..2ab8b56116a9efaac2c552a829353a135919e368 100644
--- a/frontend/src/pages/student/StudentLayout.vue
+++ b/frontend/src/pages/student/StudentLayout.vue
@@ -42,6 +42,7 @@
 
 <script>
 import { mapState } from 'vuex'
+import {UI} from '@/store/modules/ui'
 import BaseLayout from '@/components/BaseLayout'
 import ExamInformation from '@/components/student/ExamInformation'
 export default {
@@ -63,9 +64,9 @@ export default {
       moduleReference: state => state.studentPage.exam.moduleReference,
       submissions: state => state.studentPage.submissionsForList,
       exam: state => state.studentPage.exam,
-      visited: state => state.studentPage.visited,
-      mini: state => state.ui.sideBarCollapsed
+      visited: state => state.studentPage.visited
     }),
+    mini: function () { return UI.state.mini },
     submissionNavItems: function () {
       return this.submissions.map((sub, index) => {
         return {
diff --git a/frontend/src/store/getters.ts b/frontend/src/store/getters.ts
index c36c0d45d106f7a8292c35429312ebc9789aa546..6d4aafded1ef2b08b0cb013ea40397db819499bd 100644
--- a/frontend/src/store/getters.ts
+++ b/frontend/src/store/getters.ts
@@ -10,12 +10,12 @@ const correctedGetter = mb.read(function corrected (state) {
 })
 const submissionGetter = mb.read(function submission (state) {
   return (pk: string) => {
-      return state.submissions[pk]
+    return state.submissions[pk]
   }
 })
 const submissionTypeGetter = mb.read(function submissionType (state) {
   return (pk: string) => {
-      return state.submissionTypes[pk]
+    return state.submissionTypes[pk]
   }
 })
 
diff --git a/frontend/src/store/modules/ui.ts b/frontend/src/store/modules/ui.ts
index b1760cea54c4250af73939c126485a1ff7e768e3..776384463438ccb8bfb091c4118d568a3e350abd 100644
--- a/frontend/src/store/modules/ui.ts
+++ b/frontend/src/store/modules/ui.ts
@@ -1,14 +1,14 @@
-import {Module} from 'vuex'
+import {getStoreBuilder} from 'vuex-typex'
 import {RootState} from '@/store/store'
 
-interface UiState {
+export interface UIState {
   sideBarCollapsed: boolean
   darkMode: boolean
   darkModeUnlocked: boolean
   showJumbotron: boolean
 }
 
-function initialState (): UiState {
+function initialState (): UIState {
   return {
     sideBarCollapsed: false,
     darkMode: false,
@@ -17,29 +17,30 @@ function initialState (): UiState {
   }
 }
 
-export const uiMut = Object.freeze({
-  SET_SIDEBAR_COLLAPSED: 'SET_SIDEBAR_COLLAPSED',
-  SET_DARK_MODE: 'SET_DARK_MODE',
-  SET_DARK_MODE_UNLOCKED: 'SET_DARK_MODE_UNLOCKED',
-  SET_SHOW_JUMBOTRON: 'SET_SHOW_JUMBOTRON'
-})
-
-const ui: Module<UiState, RootState> = {
-  state: initialState(),
-  mutations: {
-    [uiMut.SET_SIDEBAR_COLLAPSED] (state, collapsed: boolean) {
-      state.sideBarCollapsed = collapsed
-    },
-    [uiMut.SET_DARK_MODE] (state, val: boolean) {
-      state.darkMode = val
-    },
-    [uiMut.SET_DARK_MODE_UNLOCKED] (state, val: boolean) {
-      state.darkModeUnlocked = val
-    },
-    [uiMut.SET_SHOW_JUMBOTRON] (state, val: boolean) {
-      state.showJumbotron = val
-    }
-  }
+const mb = getStoreBuilder<RootState>().module('UI', initialState())
+
+
+const stateGetter = mb.state()
+
+
+function SET_SIDEBAR_COLLAPSED (state: UIState, collapsed: boolean) {
+  state.sideBarCollapsed = collapsed
+}
+function SET_DARK_MODE (state: UIState, val: boolean) {
+  state.darkMode = val
+}
+function SET_DARK_MODE_UNLOCKED (state: UIState, val: boolean) {
+  state.darkModeUnlocked = val
+}
+function SET_SHOW_JUMBOTRON (state: UIState, val: boolean) {
+  state.showJumbotron = val
 }
 
-export default ui
+export const UI = {
+  get state() { return stateGetter() },
+
+  SET_SIDEBAR_COLLAPSED: mb.commit(SET_SIDEBAR_COLLAPSED),
+  SET_DARK_MODE: mb.commit(SET_DARK_MODE),
+  SET_DARK_MODE_UNLOCKED: mb.commit(SET_DARK_MODE_UNLOCKED),
+  SET_SHOW_JUMBOTRON: mb.commit(SET_SHOW_JUMBOTRON)
+}
diff --git a/frontend/src/store/store.ts b/frontend/src/store/store.ts
index c7379d0ccccc7f37af47ccf7a6588ef9a4855ed3..e6ca81843fe422c872d6b243693148cac3df715c 100644
--- a/frontend/src/store/store.ts
+++ b/frontend/src/store/store.ts
@@ -6,7 +6,6 @@ import {getStoreBuilder} from 'vuex-typex'
 import studentPage from './modules/student-page'
 import submissionNotes from './modules/submission-notes'
 import authentication from './modules/authentication'
-import ui from './modules/ui'
 import subscriptions from './modules/subscriptions'
 import feedbackTable from './modules/feedback_list/feedback-table'
 import feedbackSearchOptions from './modules/feedback_list/feedback-search-options'
@@ -14,6 +13,10 @@ import feedbackSearchOptions from './modules/feedback_list/feedback-search-optio
 import './mutations'
 import './actions'
 import './getters'
+
+import './modules/ui'
+import {UIState} from './modules/ui'
+
 import {lastInteraction} from '@/store/plugins/lastInteractionPlugin'
 import {
   Exam, Feedback,
@@ -25,7 +28,7 @@ import {
 
 Vue.use(Vuex)
 
-export interface RootState {
+export interface RootInitialState {
     lastAppInteraction: number
     examTypes: {[pk: string]: Exam}
     feedback: {[pk: number]: Feedback}
@@ -37,7 +40,11 @@ export interface RootState {
     tutors: Array<Tutor>
 }
 
-export function initialState (): RootState {
+export interface RootState extends RootInitialState{
+    UI: UIState
+}
+
+export function initialState (): RootInitialState {
   return {
     lastAppInteraction: Date.now(),
     examTypes: {},
@@ -64,7 +71,6 @@ const store = getStoreBuilder<RootState>().vuexStore({
     authentication,
     studentPage,
     submissionNotes,
-    ui,
     subscriptions,
     feedbackTable,
     feedbackSearchOptions
@@ -76,12 +82,13 @@ const store = getStoreBuilder<RootState>().vuexStore({
       // authentication.token is manually saved since using it with this plugin caused issues
       // when manually reloading the page
       paths: Object.keys(initialState()).concat(
-        ['ui', 'studentPage', 'submissionNotes', 'feedbackSearchOptions', 'subscriptions',
+        ['UI', 'studentPage', 'submissionNotes', 'feedbackSearchOptions', 'subscriptions',
           'authentication.user', 'authentication.jwtTimeDelta',
           'authentication.tokenCreationTime'])
     }),
     lastInteraction],
-  state: initialState()
+  // TODO is there a better way than casting the initialState ?
+  state: <RootState> initialState()
 })
 
 export default store
diff --git a/frontend/src/util/helpers.ts b/frontend/src/util/helpers.ts
index 11f1d8fe8112c194580df5c05456b0aaf6392822..8d8fe65cd457ba1dfd64a123c41fce51c59d14a8 100644
--- a/frontend/src/util/helpers.ts
+++ b/frontend/src/util/helpers.ts
@@ -1,5 +1,6 @@
 import {AxiosError} from "axios";
 import {Dispatch} from "vuex";
+import {MutationHandler} from "vuex-typex";
 
 export function nameSpacer (namespace: string) {
   return function (commitType: string) {
@@ -24,9 +25,9 @@ export function getObjectValueByPath (obj: any, path: string): any {
   return obj
 }
 
-interface GetSetPair {
+interface GetSetPair<P> {
     get: () => any,
-    set: (val: object) => void
+    set: (val: P) => void
 }
 
 /**
@@ -38,15 +39,19 @@ interface GetSetPair {
  * @param namespace to prepend the mutation type with
  * @returns {*}
  */
-export function createComputedGetterSetter (
+export function createComputedGetterSetter<P> (
   {path, mutation, namespace}:
-  {path: string, mutation: string, namespace:string}): GetSetPair {
+  {path: string, mutation: string | ((payload?: P) => void), namespace:string}): GetSetPair<P> {
   return {
     get (): any {
       return getObjectValueByPath((this as any).$store.state, path)
     },
-    set (val: object): void {
-        (this as any).$store.commit(`${namespace ? namespace + '/' : ''}${mutation}`, val)
+    set (val: P): void {
+      if (typeof mutation === "string") {
+          (this as any).$store.commit(`${namespace ? namespace + '/' : ''}${mutation}`, val)
+      } else {
+        mutation(val)
+      }
     }
   }
 }
@@ -58,7 +63,7 @@ interface StateMapperItem {
 }
 
 interface MappedState {
-    [key: string]: GetSetPair
+    [key: string]: GetSetPair<any>
 }
 
 /**
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index b91413a1e4b1c625208da60fd2b699dfa1edaa67..924b2c18bbde969f55b052c846e5041e60918174 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -6931,8 +6931,9 @@ vuex-persistedstate@^2.5.4:
 
 "vuex-typex@https://github.com/robinhundt/vuex-typex.git":
   version "3.0.1"
-  resolved "https://github.com/robinhundt/vuex-typex.git#72c5eb30ac7fe7c4bf657ebe4e40e115f309fa39"
+  resolved "https://github.com/robinhundt/vuex-typex.git#3e0da4d1e01eef6e0eed609ef97cb036ca8a692f"
   dependencies:
+    deepmerge "^2.1.1"
     vuex "^3.0.0"
 
 vuex@^3.0.0, vuex@^3.0.1: