diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.html b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.html
index d324f8d83fe91defe9b5066f4f24d230bc33eb4f..3e7af75f493ada03112994766ea980b90033e282 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.html
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.html
@@ -1,24 +1,27 @@
-<h1 class="heading-1 pb-4">Organisationseinheiten</h1>
-<p id="absender-desc" class="p-1">Hinterlegen Sie Name und ID der Organisationseinheiten.</p>
+<ng-container *ngIf="organisationseinheitItems$ | async as organisationseinheitItems">
+  <h1 class="heading-1 pb-4">Organisationseinheiten</h1>
+  <p id="absender-desc" class="p-1">Hinterlegen Sie Name und ID der Organisationseinheiten.</p>
 
-<admin-organisationseinheit-form
-  data-test-id="organisationseinheit-form"
-></admin-organisationseinheit-form>
+  <admin-organisationseinheit-form
+    data-test-id="organisationseinheit-form"
+    [organisationseinheitItems]="organisationseinheitItems"
+  ></admin-organisationseinheit-form>
 
-<admin-secondary-button
-  (clickEmitter)="openDialogForNewGroup()"
-  data-test-id="organisationseinheit-open-dialog-button"
-  label="Neue Organisationseinheit anlegen"
->
-</admin-secondary-button>
-<admin-spinner
-  data-test-id="organisationseinheit-spinner"
-  *ngIf="deleteInProgress$ | async"
-></admin-spinner>
+  <admin-secondary-button
+    (clickEmitter)="openDialogForNewGroup()"
+    data-test-id="organisationseinheit-open-dialog-button"
+    label="Neue Organisationseinheit anlegen"
+  >
+  </admin-secondary-button>
+  <admin-spinner
+    data-test-id="organisationseinheit-spinner"
+    *ngIf="deleteInProgress$ | async"
+  ></admin-spinner>
 
-<admin-organisationseinheit-list
-  [organisationseinheitItems]="organisationseinheitItems$ | async"
-  (editOrganisationseinheit)="edit($event)"
-  (deleteOrganisationseinheit)="delete($event)"
-  data-test-id="organisationseinheit-list"
-></admin-organisationseinheit-list>
+  <admin-organisationseinheit-list
+    [organisationseinheitItems]="organisationseinheitItems"
+    (editOrganisationseinheit)="edit($event)"
+    (deleteOrganisationseinheit)="delete($event)"
+    data-test-id="organisationseinheit-list"
+  ></admin-organisationseinheit-list>
+</ng-container>
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.spec.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.spec.ts
index 50aed3b14f080f41d6dd560101a3c1a358bc5b8f..126c1e2dbcc1bf491d15a23b982b8481996c078e 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.spec.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.spec.ts
@@ -1,3 +1,4 @@
+import { createStateResource } from '@alfa-client/tech-shared';
 import {
   Mock,
   dispatchEventFromFixture,
@@ -11,14 +12,11 @@ import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { singleCold } from 'libs/tech-shared/test/marbles';
 import { MockComponent } from 'ng-mocks';
 import { of } from 'rxjs';
-import {
-  createOrganisationseinheit,
-  createOrganisationseinheitState,
-} from '../../../../test/user/user';
+import { createOrganisationseinheit } from '../../../../test/user/user';
 import { SecondaryButtonComponent } from '../../shared/secondary-button/secondary-button.component';
 import { SpinnerComponent } from '../../shared/spinner/spinner.component';
 import { Organisationseinheit } from '../../user/user.model';
-import { UserService } from '../../user/user.service';
+import { OrganisationseinheitService } from '../organisationseinheitService';
 import { OrganisationseinheitContainerComponent } from './organisationseinheit-container.component';
 import { OrganisationseinheitFormComponent } from './organisationseinheit-form/organisationseinheit-form.component';
 import { OrganisationseinheitListComponent } from './organisationseinheit-list/organisationseinheit-list.component';
@@ -27,7 +25,9 @@ describe('OrganisationseinheitContainerComponent', () => {
   let component: OrganisationseinheitContainerComponent;
   let fixture: ComponentFixture<OrganisationseinheitContainerComponent>;
 
-  const userService: Mock<UserService> = mock(UserService);
+  const organisationseinheitService: Mock<OrganisationseinheitService> = mock(
+    OrganisationseinheitService,
+  );
 
   const dialogOpenButtonSelector: string = getDataTestIdOf(
     'organisationseinheit-open-dialog-button',
@@ -48,15 +48,15 @@ describe('OrganisationseinheitContainerComponent', () => {
         MockComponent(OrganisationseinheitListComponent),
         MockComponent(SpinnerComponent),
       ],
-      providers: [{ provide: UserService, useValue: userService }],
+      providers: [{ provide: OrganisationseinheitService, useValue: organisationseinheitService }],
     }).compileComponents();
 
     fixture = TestBed.createComponent(OrganisationseinheitContainerComponent);
     component = fixture.componentInstance;
 
-    userService.getOrganisationseinheitState = jest
+    organisationseinheitService.get = jest
       .fn()
-      .mockReturnValue(of(createOrganisationseinheitState(organisationseinheitItems)));
+      .mockReturnValue(of(createStateResource(organisationseinheitItems)));
     fixture.detectChanges();
 
     formComponent = getElementFromFixtureByType(fixture, OrganisationseinheitFormComponent);
@@ -99,13 +99,13 @@ describe('OrganisationseinheitContainerComponent', () => {
     const organisationseinheit: Organisationseinheit = organisationseinheitItems[0];
 
     beforeEach(() => {
-      userService.deleteOrganisationseinheit = jest.fn().mockReturnValue(singleCold(true));
+      organisationseinheitService.delete = jest.fn().mockReturnValue(singleCold(true));
     });
 
     it('should call service method', () => {
       component.delete(organisationseinheit);
 
-      expect(userService.deleteOrganisationseinheit).toHaveBeenCalledWith(organisationseinheit.id);
+      expect(organisationseinheitService.delete).toHaveBeenCalledWith(organisationseinheit.id);
     });
 
     it('should assign delete progress observable', () => {
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.ts
index f2bc2061e143c013c4d7f9f3096c2020c8852d3a..b85e0c8447ec080e397018c686a0f44703e58840 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.ts
@@ -1,7 +1,8 @@
+import { StateResource } from '@alfa-client/tech-shared';
 import { Component, OnInit, ViewChild } from '@angular/core';
 import { Observable, of } from 'rxjs';
 import { Organisationseinheit } from '../../user/user.model';
-import { UserService } from '../../user/user.service';
+import { OrganisationseinheitService } from '../organisationseinheitService';
 import { OrganisationseinheitFormComponent } from './organisationseinheit-form/organisationseinheit-form.component';
 
 @Component({
@@ -9,16 +10,16 @@ import { OrganisationseinheitFormComponent } from './organisationseinheit-form/o
   templateUrl: './organisationseinheit-container.component.html',
 })
 export class OrganisationseinheitContainerComponent implements OnInit {
-  organisationseinheitItems$: Observable<Organisationseinheit[]>;
+  organisationseinheitItems$: Observable<StateResource<Organisationseinheit[]>>;
   deleteInProgress$: Observable<boolean> = of(false);
 
   @ViewChild(OrganisationseinheitFormComponent)
   private form!: OrganisationseinheitFormComponent;
 
-  constructor(private userService: UserService) {}
+  constructor(private organisationseinheitService: OrganisationseinheitService) {}
 
   ngOnInit(): void {
-    this.organisationseinheitItems$ = this.userService.getOrganisationseinheitItems();
+    this.organisationseinheitItems$ = this.organisationseinheitService.get();
   }
 
   public openDialogForNewGroup(): void {
@@ -30,6 +31,6 @@ export class OrganisationseinheitContainerComponent implements OnInit {
   }
 
   public delete(organisationseinheit: Organisationseinheit): void {
-    this.deleteInProgress$ = this.userService.deleteOrganisationseinheit(organisationseinheit.id);
+    this.deleteInProgress$ = this.organisationseinheitService.delete(organisationseinheit.id);
   }
 }
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.html b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.html
index 8d00b44b3737090091e15a34e731f4168b12b601..3bd257438d0545a41b7b791b9574b1cf9184b009 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.html
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.html
@@ -1,3 +1,4 @@
+<ng-container *ngIf="submitInProgress$ | async"></ng-container>
 <dialog #OrganisationseinheitDialog data-test-id="organisationseinheit-dialog" class="bg-gray-50">
   <button
     (click)="OrganisationseinheitDialog.close()"
@@ -21,13 +22,13 @@
       [formControlName]="OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD"
     ></text-field>
 
-    <admin-primary-button
+    <ods-button-with-spinner
       data-test-id="organisationseinheit-save-button"
       class="justify-self-end"
       (clickEmitter)="submit()"
-      [submitInProgress]="submitInProgress$ | async"
-      label="Speichern"
+      [stateResource]="organisationseinheitItems"
+      text="Speichern"
     >
-    </admin-primary-button>
+    </ods-button-with-spinner>
   </form>
 </dialog>
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.ts
index 5224f6db0c0c1abd27fba74b2adc3067fe00a460..9796922d5e713c9ff2bcc2964d0c70d94f9c4572 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.ts
@@ -1,4 +1,5 @@
-import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
+import { StateResource, createStateResource } from '@alfa-client/tech-shared';
+import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core';
 import { Observable, of, tap } from 'rxjs';
 import { Organisationseinheit } from '../../../user/user.model';
 import { OrganisationseinheitFormservice } from './organisationseinheit.formservice';
@@ -9,6 +10,9 @@ import { OrganisationseinheitFormservice } from './organisationseinheit.formserv
   providers: [OrganisationseinheitFormservice],
 })
 export class OrganisationseinheitFormComponent implements AfterViewInit {
+  @Input()
+  organisationseinheitItems: StateResource<Organisationseinheit[]> = createStateResource([]);
+
   static CREATE_LABEL: string = 'Neue Organisationseinheit anlegen';
   static EDIT_LABEL: string = 'Organisationseinheit bearbeiten';
 
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.ts
index 850b5f775f723f0b27073ac5de0b99d7a2c877e8..3309b9a813a1158fc08e7ca007e35d9f9f90475d 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.ts
@@ -1,17 +1,20 @@
-import { isNotNil } from '@alfa-client/tech-shared';
-import { Injectable } from '@angular/core';
+import { createStateResource, isNotNil, StateResource } from '@alfa-client/tech-shared';
+import { Injectable, Input } from '@angular/core';
 import { AbstractControl, FormControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
-import { Observable, catchError, of } from 'rxjs';
+import { catchError, Observable, of } from 'rxjs';
 import {
   Organisationseinheit,
   OrganisationseinheitError,
   OrganisationseinheitErrorType,
 } from '../../../user/user.model';
-import { UserService } from '../../../user/user.service';
 import { getOrganisationseinheitErrorMessage } from '../../../user/user.util';
+import { OrganisationseinheitService } from '../../organisationseinheitService';
 
 @Injectable()
 export class OrganisationseinheitFormservice {
+  @Input()
+  organisationseinheitItems: StateResource<Organisationseinheit[]> = createStateResource([]);
+
   public static readonly ORGANISATIONSEINHEIT_NAME_FIELD: string = 'name';
   public static readonly ORGANISATIONSEINHEIT_IDS_FIELD: string = 'organisationseinheit';
 
@@ -21,7 +24,7 @@ export class OrganisationseinheitFormservice {
 
   constructor(
     private formBuilder: UntypedFormBuilder,
-    private userService: UserService,
+    private organisationsEinheitService: OrganisationseinheitService,
   ) {
     this.form = this.formBuilder.group({
       [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD]: new FormControl(''),
@@ -47,14 +50,14 @@ export class OrganisationseinheitFormservice {
   }
 
   create(): Observable<boolean> {
-    return this.userService.createOrganisationseinheit(
-      this.getName(),
-      this.getOrganisationseinheitIds(),
-    );
+    return this.organisationsEinheitService.create({
+      name: this.getName(),
+      organisationseinheitIds: this.getOrganisationseinheitIds(),
+    });
   }
 
   save(): Observable<boolean> {
-    return this.userService.saveOrganisationseinheit({
+    return this.organisationsEinheitService.save({
       ...this.source,
       name: this.getName(),
       organisationseinheitIds: this.getOrganisationseinheitIds(),
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.html b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.html
index f26e6e0c0d028d7d8bf3b224279cf662d80e5603..35f04a2f2e65d9cd6354ccc65e4ebe980c7ad8bb 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.html
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.html
@@ -1,52 +1,54 @@
-<table
-  *ngIf="organisationseinheitItems.length; else emptyMessage"
-  aria-label="Keycloak-Gruppen mit OrganisationseinheitIDs"
-  class="mb-2 mt-2 table-fixed"
-  data-test-id="organisationseinheit-table"
->
-  <tr class="invisible">
-    <th scope="col">Name</th>
-    <th scope="col">Attribute</th>
-  </tr>
-  <tr *ngFor="let organisationseinheit of organisationseinheitItems" [id]="organisationseinheit.id">
-    <td
-      [attr.data-test-id]="
-        'organisationseinheit-name-' + organisationseinheit.id | convertForDataTest
-      "
-      class="w-96 border border-slate-500 p-2 font-bold"
-    >
-      {{ organisationseinheit.name }}
-    </td>
-    <td
-      [attr.data-test-id]="
-        'organisationseinheit-attr-' + organisationseinheit.id | convertForDataTest
-      "
-      class="w-96 border border-slate-500 p-2"
-    >
-      OrganisationseinheitID: {{ organisationseinheit.organisationseinheitIds.join(', ') }}
-      <admin-more-menu class="float-right">
-        <admin-more-item-button
-          (clickEmitter)="editOrganisationseinheit.emit(organisationseinheit)"
-          more-menu-item
-          [attr.data-test-id]="
-            'organisationseinheit-edit-' + organisationseinheit.id | convertForDataTest
-          "
-          label="Bearbeiten"
-        ></admin-more-item-button>
-        <admin-more-item-button
-          (clickEmitter)="deleteOrganisationseinheit.emit(organisationseinheit)"
-          more-menu-item
-          [attr.data-test-id]="
-            'organisationseinheit-delete-' + organisationseinheit.id | convertForDataTest
-          "
-          label="Löschen"
-        ></admin-more-item-button>
-      </admin-more-menu>
-    </td>
-  </tr>
-</table>
-<ng-template #emptyMessage
-  ><span data-test-id="organisationseinheit-empty-message" class="mb-2 mt-2 block italic"
-    >Keine Organisationseinheiten vorhanden.</span
+<ng-container *ngIf="organisationseinheitItems.resource">
+  <table
+    *ngIf="organisationseinheitItems.resource.length; else emptyMessage"
+    aria-label="Keycloak-Gruppen mit OrganisationseinheitIDs"
+    class="mb-2 mt-2 table-fixed"
+    data-test-id="organisationseinheit-table"
   >
-</ng-template>
+    <tr class="invisible">
+      <th scope="col">Name</th>
+      <th scope="col">Attribute</th>
+    </tr>
+    <tr *ngFor="let organisationseinheit of organisationseinheitItems.resource" [id]="organisationseinheit.id">
+      <td
+        [attr.data-test-id]="
+          'organisationseinheit-name-' + organisationseinheit.id | convertForDataTest
+        "
+        class="w-96 border border-slate-500 p-2 font-bold"
+      >
+        {{ organisationseinheit.name }}
+      </td>
+      <td
+        [attr.data-test-id]="
+          'organisationseinheit-attr-' + organisationseinheit.id | convertForDataTest
+        "
+        class="w-96 border border-slate-500 p-2"
+      >
+        OrganisationseinheitID: {{ organisationseinheit.organisationseinheitIds.join(', ') }}
+        <admin-more-menu class="float-right">
+          <admin-more-item-button
+            (clickEmitter)="editOrganisationseinheit.emit(organisationseinheit)"
+            more-menu-item
+            [attr.data-test-id]="
+              'organisationseinheit-edit-' + organisationseinheit.id | convertForDataTest
+            "
+            label="Bearbeiten"
+          ></admin-more-item-button>
+          <admin-more-item-button
+            (clickEmitter)="deleteOrganisationseinheit.emit(organisationseinheit)"
+            more-menu-item
+            [attr.data-test-id]="
+              'organisationseinheit-delete-' + organisationseinheit.id | convertForDataTest
+            "
+            label="Löschen"
+          ></admin-more-item-button>
+        </admin-more-menu>
+      </td>
+    </tr>
+  </table>
+  <ng-template #emptyMessage
+    ><span data-test-id="organisationseinheit-empty-message" class="mb-2 mt-2 block italic"
+      >Keine Organisationseinheiten vorhanden.</span
+    >
+  </ng-template>
+</ng-container>
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.spec.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.spec.ts
index 912a82f8a93e2865f011ec5a8f0c40905a910d85..53a1347003495d3b5501794c11b04af3f60008c7 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.spec.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.spec.ts
@@ -1,4 +1,9 @@
-import { ConvertForDataTestPipe, convertForDataTest } from '@alfa-client/tech-shared';
+import {
+  ConvertForDataTestPipe,
+  StateResource,
+  convertForDataTest,
+  createStateResource,
+} from '@alfa-client/tech-shared';
 import {
   dispatchEventFromFixture,
   existsAsHtmlElement,
@@ -57,10 +62,10 @@ describe('OrganisationseinheitListComponent', () => {
     });
 
     describe('with organisationseinheit items', () => {
-      const organisationseinheitItems: Organisationseinheit[] = [
+      const organisationseinheitItems: StateResource<Organisationseinheit[]> = createStateResource([
         createOrganisationseinheit(),
         createOrganisationseinheit(),
-      ];
+      ]);
       beforeEach(() => {
         component.organisationseinheitItems = organisationseinheitItems;
         fixture.detectChanges();
@@ -79,13 +84,13 @@ describe('OrganisationseinheitListComponent', () => {
         const rowIds: string[] = rows.map((row) => row.id);
 
         expect(rowIds).toEqual(
-          organisationseinheitItems.map(
+          organisationseinheitItems.resource.map(
             (organisationseinheit: Organisationseinheit) => organisationseinheit.id,
           ),
         );
       });
 
-      it.each(organisationseinheitItems)(
+      it.each(organisationseinheitItems.resource)(
         'should show name of organisationseinheit %#',
         (organisationseinheit: Organisationseinheit) => {
           const nameTableCell = getElementFromFixture(
@@ -97,7 +102,7 @@ describe('OrganisationseinheitListComponent', () => {
         },
       );
 
-      it.each(organisationseinheitItems)(
+      it.each(organisationseinheitItems.resource)(
         'should show organisationseinheitId of organisationseinheit %#',
         (organisationseinheit: Organisationseinheit) => {
           const attrTableCell = getElementFromFixture(
@@ -111,7 +116,7 @@ describe('OrganisationseinheitListComponent', () => {
         },
       );
 
-      it.each(organisationseinheitItems)(
+      it.each(organisationseinheitItems.resource)(
         'should emit editOrganisationseinheit %# on edit button click ',
         (organisationseinheit: Organisationseinheit) => {
           component.editOrganisationseinheit.emit = jest.fn();
@@ -128,7 +133,7 @@ describe('OrganisationseinheitListComponent', () => {
         },
       );
 
-      it.each(organisationseinheitItems)(
+      it.each(organisationseinheitItems.resource)(
         'should emit deleteOrganisationseinheit %# on delete button click ',
         (organisationseinheit: Organisationseinheit) => {
           component.deleteOrganisationseinheit.emit = jest.fn();
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.ts
index dadd2f0401682461a67e76f73e79dfc09afb54be..39b105cb05759aad5be906fb7b78e7b0b167dcb6 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.ts
@@ -1,3 +1,4 @@
+import { createStateResource, StateResource } from '@alfa-client/tech-shared';
 import { Component, EventEmitter, Input, Output } from '@angular/core';
 import { Organisationseinheit } from '../../../user/user.model';
 
@@ -7,7 +8,7 @@ import { Organisationseinheit } from '../../../user/user.model';
 })
 export class OrganisationseinheitListComponent {
   @Input()
-  organisationseinheitItems: Organisationseinheit[] = [];
+  organisationseinheitItems: StateResource<Organisationseinheit[]> = createStateResource([]);
 
   @Output()
   editOrganisationseinheit: EventEmitter<Organisationseinheit> = new EventEmitter();
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheitService.spec.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheitService.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..97557340dccaf5851d41a6b9bcbf55916a161ff0
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheitService.spec.ts
@@ -0,0 +1,48 @@
+import { mock, Mock, useFromMock } from '@alfa-client/test-utils';
+import { createOrganisationseinheit } from '../../../test/user/user';
+import { UserRepository } from '../user/user.repository.service';
+import { OrganisationseinheitService } from './organisationseinheitService';
+
+describe('OrganisationseinheitService', () => {
+  let service: OrganisationseinheitService;
+  let repository: Mock<UserRepository>;
+
+  const organisationseinheit = createOrganisationseinheit();
+
+  beforeEach(() => {
+    repository = mock(UserRepository);
+    service = new OrganisationseinheitService(useFromMock(repository));
+  });
+
+  describe('getItemsFromKeycloak', () => {
+    it('should call findOrganisationseinheitItems from userRepository', () => {
+      service.getItemsFromKeycloak();
+
+      expect(repository.findOrganisationseinheitItems).toHaveBeenCalled();
+    });
+  });
+
+  describe('saveInKeycloak', () => {
+    it('should call saveOrganisationseinheit from userRepository', () => {
+      service.saveInKeycloak(organisationseinheit);
+
+      expect(repository.saveOrganisationseinheit).toHaveBeenCalledWith(organisationseinheit);
+    });
+  });
+
+  describe('createInKeycloak', () => {
+    it('should call createOrganisationseinheit from userRepository', () => {
+      service.createInKeycloak(organisationseinheit);
+
+      expect(repository.createOrganisationseinheit).toHaveBeenCalledWith(organisationseinheit);
+    });
+  });
+
+  describe('deleteInKeycloak', () => {
+    it('should call deleteOrganisationseinheit from userRepository', () => {
+      service.deleteInKeycloak(organisationseinheit.id);
+
+      expect(repository.deleteOrganisationseinheit).toHaveBeenCalledWith(organisationseinheit.id);
+    });
+  });
+});
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheitService.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheitService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4bd882e2f5a1240c58b135c0136989a725c78fba
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheitService.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { KeycloakResourceService } from '../user/keycloak.resource.service';
+import { Organisationseinheit } from '../user/user.model';
+import { UserRepository } from '../user/user.repository.service';
+
+@Injectable({
+  providedIn: 'root',
+})
+export class OrganisationseinheitService extends KeycloakResourceService<Organisationseinheit> {
+  constructor(private userRepository: UserRepository) {
+    super();
+  }
+
+  getItemsFromKeycloak(): Observable<Organisationseinheit[]> {
+    return this.userRepository.findOrganisationseinheitItems();
+  }
+  saveInKeycloak(organisationseinheit: Organisationseinheit): Observable<void> {
+    return this.userRepository.saveOrganisationseinheit(organisationseinheit);
+  }
+
+  createInKeycloak(organisationseinheit: {
+    name: string;
+    organisationseinheitIds: string[];
+  }): Observable<Organisationseinheit> {
+    return this.userRepository.createOrganisationseinheit(organisationseinheit);
+  }
+
+  deleteInKeycloak(id: string): Observable<void> {
+    return this.userRepository.deleteOrganisationseinheit(id);
+  }
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.spec.ts b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f9b19d82c3bd9ca6b91cf8e723026f42de8d9d52
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.spec.ts
@@ -0,0 +1,242 @@
+import { fakeAsync, tick } from '@angular/core/testing';
+import faker from '@faker-js/faker';
+import { cold } from 'jest-marbles';
+import {
+  StateResource,
+  createEmptyStateResource,
+} from 'libs/tech-shared/src/lib/resource/resource.util';
+import { createDummy } from 'libs/tech-shared/test/dummy';
+import { singleCold } from 'libs/tech-shared/test/marbles';
+import { Observable, of } from 'rxjs';
+import * as resourceUtil from '../../../../../tech-shared/src/lib/resource/resource.util';
+import { KeycloakResourceService } from './keycloak.resource.service';
+
+describe('KeycloakResourceService', () => {
+  let service: KeycloakResourceService<unknown>;
+
+  const dummyObject = createDummy();
+  const id = faker.random.word();
+  const dummyAction = of(dummyObject);
+
+  beforeEach(() => {
+    service = new TestResourceService();
+  });
+
+  describe('get', () => {
+    beforeEach(() => {
+      service.handleChanges = jest.fn();
+    });
+
+    it('should return stateResource as observable', (done) => {
+      service.get().subscribe((stateResource) => {
+        expect(stateResource).toBe(service.stateResource.value);
+        done();
+      });
+    });
+
+    it('should call handleChanges ', fakeAsync(() => {
+      service.get().subscribe();
+
+      expect(service.handleChanges).toHaveBeenCalled();
+    }));
+  });
+
+  describe('handleChanges', () => {
+    beforeEach(() => {
+      service.loadResource = jest.fn();
+    });
+
+    it('should call loadResource when loading is required', () => {
+      jest.spyOn(resourceUtil, 'isLoadingRequired').mockReturnValue(true);
+
+      service.handleChanges(createEmptyStateResource());
+
+      expect(service.loadResource).toHaveBeenCalled();
+    });
+
+    it('should not call loadResource when loading is required', () => {
+      jest.spyOn(resourceUtil, 'isLoadingRequired').mockReturnValue(false);
+
+      service.handleChanges(createEmptyStateResource());
+
+      expect(service.loadResource).not.toHaveBeenCalled();
+    });
+  });
+
+  describe('loadResource', () => {
+    it('should call set loading', () => {
+      service.setLoading = jest.fn();
+
+      service.loadResource();
+
+      expect(service.setLoading).toHaveBeenCalled();
+    });
+
+    it('should update Resource', fakeAsync(() => {
+      const dummyItems = [createDummy(), createDummy()];
+      service.getItemsFromKeycloak = jest.fn().mockReturnValue(of(dummyItems));
+
+      service.loadResource();
+      tick();
+
+      expect(service.stateResource.value.resource).toEqual(dummyItems);
+    }));
+  });
+
+  describe('create', () => {
+    const saveObject = createDummy();
+
+    it('should call handleLoading', () => {
+      service.handleLoading = jest.fn();
+
+      service.create(saveObject);
+
+      expect(service.handleLoading).toHaveBeenCalled();
+    });
+
+    it('should call createInKeycloak', () => {
+      service.createInKeycloak = jest.fn().mockReturnValue(of({}));
+
+      service.create(saveObject);
+
+      expect(service.createInKeycloak).toHaveBeenCalled();
+    });
+  });
+
+  describe('save', () => {
+    it('should call handleLoading', () => {
+      service.handleLoading = jest.fn();
+
+      service.save(dummyObject);
+
+      expect(service.handleLoading).toHaveBeenCalled();
+    });
+
+    it('should call createInKeycloak', () => {
+      service.saveInKeycloak = jest.fn().mockReturnValue(of({}));
+
+      service.save(dummyObject);
+
+      expect(service.saveInKeycloak).toHaveBeenCalled();
+    });
+  });
+
+  describe('delete', () => {
+    it('should call handleLoading', () => {
+      service.handleLoading = jest.fn();
+
+      service.delete(id);
+
+      expect(service.handleLoading).toHaveBeenCalled();
+    });
+
+    it('should call createInKeycloak', () => {
+      service.saveInKeycloak = jest.fn().mockReturnValue(of({}));
+
+      service.save(id);
+
+      expect(service.saveInKeycloak).toHaveBeenCalled();
+    });
+  });
+
+  describe('handleLoading', () => {
+    it('should set loading', () => {
+      service.handleLoading(dummyAction);
+
+      expect(service.stateResource.value.loading).toBe(true);
+    });
+
+    it('should call refreshAfterFirstEmit', () => {
+      service.refreshAfterFirstEmit = jest.fn().mockReturnValue(dummyAction);
+
+      service.handleLoading(dummyAction);
+
+      expect(service.refreshAfterFirstEmit).toHaveBeenCalled();
+    });
+
+    it('should call progress', () => {
+      service.progress = jest.fn().mockReturnValue(dummyAction);
+
+      service.handleLoading(dummyAction);
+
+      expect(service.progress).toHaveBeenCalled();
+    });
+  });
+
+  // warum funktioniert hier fakeAsync nicht?
+  describe('refreshAfterFirstEmit', () => {
+    it('should call refresh after first emit', (done) => {
+      service.refresh = jest.fn();
+
+      service.refreshAfterFirstEmit(dummyAction).subscribe(() => {
+        expect(service.refresh).toHaveBeenCalled();
+        done();
+      });
+    });
+  });
+
+  describe('progress', () => {
+    it('should emit true at the start and false after first parameter emit', () => {
+      const result = service.progress(cold('--x', { x: dummyObject }));
+
+      expect(result).toBeObservable(cold('a-b', { a: true, b: false }));
+    });
+  });
+
+  describe('setLoading', () => {
+    it('should set loading in state to true without parameter', () => {
+      service.setLoading();
+
+      expect(service.stateResource.value.loading).toEqual(true);
+    });
+
+    it('should set loading in state to false for parameter false', () => {
+      service.setLoading(false);
+
+      expect(service.stateResource.value.loading).toEqual(false);
+    });
+  });
+
+  describe('refresh', () => {
+    it('should set reload in state to true', () => {
+      service.refresh();
+
+      expect(service.stateResource.value.reload).toBe(true);
+    });
+
+    it('should clear resource in state', () => {
+      service.refresh();
+
+      expect(service.stateResource.value.resource).toBe(null);
+    });
+  });
+
+  describe('select resource', () => {
+    it('should return state resource', () => {
+      const stateResource = createEmptyStateResource<unknown[]>();
+      service.stateResource.next(stateResource);
+
+      const resource$: Observable<StateResource<unknown[]>> = service.selectResource();
+
+      expect(resource$).toBeObservable(singleCold(stateResource));
+    });
+  });
+});
+
+class TestResourceService extends KeycloakResourceService<unknown> {
+  getItemsFromKeycloak(): Observable<unknown[]> {
+    return of([null]);
+  }
+
+  saveInKeycloak(): Observable<void> {
+    return of(null);
+  }
+
+  createInKeycloak(): Observable<void> {
+    return of(null);
+  }
+
+  deleteInKeycloak(): Observable<void> {
+    return of(null);
+  }
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.ts b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7ed82d400b566d68ba97b19d902bd446b1d9e12d
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.ts
@@ -0,0 +1,94 @@
+import {
+  createEmptyStateResource,
+  createStateResource,
+  isLoadingRequired,
+  StateResource,
+} from '@alfa-client/tech-shared';
+import { BehaviorSubject, first, map, Observable, startWith, tap } from 'rxjs';
+
+// KeycloakListResourceService?
+export abstract class KeycloakResourceService<T> {
+  readonly stateResource: BehaviorSubject<StateResource<T[]>> = new BehaviorSubject(
+    createEmptyStateResource(),
+  );
+
+  public get() {
+    return this.stateResource
+      .asObservable()
+      .pipe(tap((stateResource) => this.handleChanges(stateResource)));
+  }
+
+  handleChanges(stateResource: StateResource<T[]>) {
+    if (isLoadingRequired(stateResource)) {
+      this.loadResource();
+    }
+  }
+
+  loadResource(): void {
+    this.setLoading();
+    this.getItemsFromKeycloak()
+      .pipe(first())
+      .subscribe((items) => this.updateResource(items));
+  }
+
+  abstract getItemsFromKeycloak(): Observable<T[]>;
+
+  private updateResource(items: T[]) {
+    this.stateResource.next(createStateResource(items));
+  }
+
+  public create(item: Partial<T>): Observable<boolean> {
+    return this.handleLoading(this.createInKeycloak(item));
+  }
+
+  abstract createInKeycloak(item: Partial<T>): Observable<T>;
+
+  public save(item: T): Observable<boolean> {
+    return this.handleLoading(this.saveInKeycloak(item));
+  }
+
+  abstract saveInKeycloak(item: T): Observable<void>;
+
+  public delete(id: string): Observable<boolean> {
+    return this.handleLoading(this.deleteInKeycloak(id));
+  }
+
+  abstract deleteInKeycloak(id: string): Observable<void>;
+
+  handleLoading(action: Observable<unknown>): Observable<boolean> {
+    this.setLoading();
+    return this.progress(this.refreshAfterFirstEmit(action));
+  }
+
+  refreshAfterFirstEmit(action: Observable<unknown>): Observable<unknown> {
+    return action.pipe(
+      first(),
+      tap(() => this.refresh()),
+    );
+  }
+
+  progress(action: Observable<unknown>): Observable<boolean> {
+    return action.pipe(
+      map(() => false),
+      startWith(true),
+    );
+  }
+
+  setLoading(loading: boolean = true): void {
+    this.stateResource.next({
+      ...this.stateResource.value,
+      loading,
+    });
+  }
+
+  refresh(): void {
+    this.stateResource.next({
+      ...createEmptyStateResource(),
+      reload: true,
+    });
+  }
+
+  public selectResource(): Observable<StateResource<T[]>> {
+    return this.stateResource.asObservable();
+  }
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts b/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts
index 72aec105655334902e5b61799f314c4dcc479eb7..bca73c460b000f7480db5bba114929d034c7d67b 100644
--- a/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts
+++ b/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts
@@ -72,21 +72,20 @@ export class UserRepository {
     ).pipe(this.rethrowMappedGroupsError());
   }
 
-  public createOrganisationseinheit(
-    name: string,
-    organisationseinheitIds: string[],
-  ): Observable<Organisationseinheit> {
+  public createOrganisationseinheit(organisationseinheit: {
+    name: string;
+    organisationseinheitIds: string[];
+  }): Observable<Organisationseinheit> {
     return from(
       this.kcAdminClient.groups.create({
-        name,
-        attributes: { organisationseinheitId: organisationseinheitIds },
+        name: organisationseinheit.name,
+        attributes: { organisationseinheitId: organisationseinheit.organisationseinheitIds },
       }),
     ).pipe(
       map(
         ({ id }): Organisationseinheit => ({
+          ...organisationseinheit,
           id,
-          name,
-          organisationseinheitIds: organisationseinheitIds,
         }),
       ),
       this.rethrowMappedGroupsError(),
diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.service.ts b/alfa-client/libs/admin/settings/src/lib/user/user.service.ts
index e8ace5eaa78c6121639bccb6f16ad79311bc3f77..4dd8938c040e2f5dcc53b1f3cf8cc41e609dd61f 100644
--- a/alfa-client/libs/admin/settings/src/lib/user/user.service.ts
+++ b/alfa-client/libs/admin/settings/src/lib/user/user.service.ts
@@ -42,7 +42,7 @@ export class UserService {
     organisationseinheitIds: string[],
   ): Observable<boolean> {
     return this.setLoadingUntilFirst(
-      this.userRepository.createOrganisationseinheit(name, organisationseinheitIds),
+      this.userRepository.createOrganisationseinheit({ name, organisationseinheitIds }),
       (organisationseinheit: Organisationseinheit) => {
         this.addOrganisationseinheit(organisationseinheit);
       },
diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/userAndRolesService.spec.ts b/alfa-client/libs/admin/settings/src/lib/users-roles/userAndRolesService.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8335ce2e8d416270dccf93a3c3fa0e655e2251dc
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/users-roles/userAndRolesService.spec.ts
@@ -0,0 +1,21 @@
+import { mock, Mock, useFromMock } from '@alfa-client/test-utils';
+import { UserRepository } from '../user/user.repository.service';
+import { UserAndRolesService } from './userAndRolesService';
+
+describe('OrganisationseinheitService', () => {
+  let service: UserAndRolesService;
+  let repository: Mock<UserRepository>;
+
+  beforeEach(() => {
+    repository = mock(UserRepository);
+    service = new UserAndRolesService(useFromMock(repository));
+  });
+
+  describe('getItemsFromKeycloak', () => {
+    it('should call findOrganisationseinheitItems from userRepository', () => {
+      service.getItemsFromKeycloak();
+
+      expect(repository.getUsers).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/userAndRolesService.ts b/alfa-client/libs/admin/settings/src/lib/users-roles/userAndRolesService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..33cea0dc83abbd108ebc19e6d19c41772c99de14
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/users-roles/userAndRolesService.ts
@@ -0,0 +1,30 @@
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { KeycloakResourceService } from '../user/keycloak.resource.service';
+import { User } from '../user/user.model';
+import { UserRepository } from '../user/user.repository.service';
+
+@Injectable({
+  providedIn: 'root',
+})
+export class UserAndRolesService extends KeycloakResourceService<User> {
+  constructor(private userRepository: UserRepository) {
+    super();
+  }
+
+  getItemsFromKeycloak(): Observable<User[]> {
+    return this.userRepository.getUsers();
+  }
+
+  createInKeycloak(item: Partial<User>): Observable<User> {
+    throw new Error('Method not implemented.');
+  }
+
+  saveInKeycloak(item: User): Observable<void> {
+    throw new Error('Method not implemented.');
+  }
+
+  deleteInKeycloak(id: string): Observable<void> {
+    throw new Error('Method not implemented.');
+  }
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.html b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.html
index a62acb25d8136a1bdb913f30b00b2b6347334f5e..96bab232f6ade64a1f96eff377da82bc77922195 100644
--- a/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.html
+++ b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.html
@@ -2,7 +2,7 @@
 <ods-button-with-spinner text="Benutzer hinzufügen" class="py-8" dataTestId="add-user-button" />
 <ng-container *ngIf="users$ | async as users">
   <ul>
-    <li *ngFor="let user of users">
+    <li *ngFor="let user of users.resource">
       {{ user.firstName }}
     </li>
   </ul>
diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts
index 05f641c948593ea3fefa0771d8eee46d41e070fe..f7adf7487c55c682370c0146fc52ff3daeb65be6 100644
--- a/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts
+++ b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts
@@ -1,7 +1,8 @@
 import { Component } from '@angular/core';
+import { StateResource } from '@alfa-client/tech-shared';
 import { Observable } from 'rxjs';
 import { User } from '../user/user.model';
-import { UserService } from '../user/user.service';
+import { UserAndRolesService } from './userAndRolesService';
 
 @Component({
   selector: 'admin-users-roles',
@@ -9,9 +10,9 @@ import { UserService } from '../user/user.service';
   styleUrl: './users-roles.component.scss',
 })
 export class UsersRolesComponent {
-  users$: Observable<User[]>;
+  users$: Observable<StateResource<User[]>>;
 
-  constructor(private userService: UserService) {
-    this.users$ = this.userService.getUsers();
+  constructor(private userAndRolesService: UserAndRolesService) {
+    this.users$ = this.userAndRolesService.get();
   }
 }
diff --git a/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts b/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts
index 2489bb3d94ad7f490abf17231a075dc0050700c2..cc180a4ec9069d0946eb9dcaaa3be7d270eb82ab 100644
--- a/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts
+++ b/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts
@@ -2,7 +2,6 @@ import { CommandResource, hasCommandError } from '@alfa-client/command-shared';
 import { StateResource, createEmptyStateResource, isLoaded } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
 import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
-import { Resource } from '@ngxp/rest';
 import { ButtonComponent, ErrorMessageComponent, buttonVariants } from '@ods/system';
 import { VariantProps } from 'class-variance-authority';
 import { isNil } from 'lodash-es';
@@ -33,7 +32,7 @@ type ButtonVariants = VariantProps<typeof buttonVariants>;
 export class ButtonWithSpinnerComponent implements OnInit {
   @Input() text: string = '';
   @Input() dataTestId: string = '';
-  @Input() stateResource: StateResource<Resource>;
+  @Input() stateResource: StateResource<unknown>;
   @Input() variant: ButtonVariants['variant'] = 'primary';
   @Input() size: ButtonVariants['size'] = 'medium';
 
@@ -43,8 +42,8 @@ export class ButtonWithSpinnerComponent implements OnInit {
     this.stateResource = this.getStateResource();
   }
 
-  getStateResource(): StateResource<Resource> {
-    return isNil(this.stateResource) ? createEmptyStateResource<Resource>() : this.stateResource;
+  getStateResource(): StateResource<unknown> {
+    return isNil(this.stateResource) ? createEmptyStateResource<unknown>() : this.stateResource;
   }
 
   get isLoading(): boolean {