diff --git a/resources/i18n/en.json b/resources/i18n/en.json
index 814adba9a734788b0d5e55847da76412292948ea..a4f90149803324b5d06acc6161ef69dbed824900 100644
--- a/resources/i18n/en.json
+++ b/resources/i18n/en.json
@@ -42,6 +42,7 @@
       "head": "Collections of this Community"
     },
     "edit": {
+      "head": "Edit collction",
       "name": "Name",
       "description": "Short Description",
       "introductory": "Introductory text (HTML)",
diff --git a/src/app/+collection-page/create-collection-page/create-collection-page.component.ts b/src/app/+collection-page/create-collection-page/create-collection-page.component.ts
index a8ee329a0f496941a2f93080ab621efc2c442b86..d934e1d7a0c6cf7b4c324432ea38bfb7b30acb6d 100644
--- a/src/app/+collection-page/create-collection-page/create-collection-page.component.ts
+++ b/src/app/+collection-page/create-collection-page/create-collection-page.component.ts
@@ -38,7 +38,7 @@ export class CreateCollectionPageComponent {
 
   onSubmit(data: any) {
     this.parentUUID$.pipe(take(1)).subscribe((uuid: string) => {
-      const collection = Object.assign(new NormalizedCollection(), {
+      const collection = Object.assign(new Collection(), {
         name: data.name,
         metadata: [
           { key: 'dc.description', value: data.introductory },
diff --git a/src/app/+community-page/community-form/community-form.component.html b/src/app/+community-page/community-form/community-form.component.html
index 578e2a0d6acc4459b5bc3e5e5e77ffa86baf7543..637506f86d5f304b8b4682160cb01756f9633c04 100644
--- a/src/app/+community-page/community-form/community-form.component.html
+++ b/src/app/+community-page/community-form/community-form.component.html
@@ -1,27 +1,4 @@
-<form #form="ngForm" (ngSubmit)="onSubmit(form.value)" class="row" action="/">
-  <div class="col-12 form-group">
-    <label for="community-name" class="font-weight-bold">{{ 'community.edit.name' | translate }}</label>
-    <input type="text" [(ngModel)]="name" name="name" id="community-name" class="form-control" [ngClass]="{'is-invalid' : !name && nameRequiredError}" aria-label="Community Name" />
-    <div class="invalid-feedback">{{ 'community.edit.required.name' | translate }}</div>
-  </div>
-  <div class="col-12 form-group">
-    <label for="community-description" class="font-weight-bold">{{ 'community.edit.description' | translate }}</label>
-    <input type="text" [(ngModel)]="description" name="description" id="community-description" class="form-control" aria-label="Community Short Description" />
-  </div>
-  <div class="col-12 form-group">
-    <label for="community-introductory" class="font-weight-bold">{{ 'community.edit.introductory' | translate }}</label>
-    <textarea [(ngModel)]="introductory" name="introductory" id="community-introductory" class="form-control" aria-label="Community Introductory Text" rows="6" ></textarea>
-  </div>
-  <div class="col-12 form-group">
-    <label for="community-copyright" class="font-weight-bold">{{ 'community.edit.copyright' | translate }}</label>
-    <textarea [(ngModel)]="copyright" name="copyright" id="community-copyright" class="form-control" aria-label="Community Copyright Text" rows="6" ></textarea>
-  </div>
-  <div class="col-12 form-group">
-    <label for="community-news" class="font-weight-bold">{{ 'community.edit.news' | translate }}</label>
-    <textarea [(ngModel)]="news" name="news" id="community-news" class="form-control" aria-label="Community News" rows="6" ></textarea>
-  </div>
-  <div class="col-12 form-group">
-    <button type="button" class="btn btn-secondary" id="community-cancel" (click)="cancel()">{{ 'community.edit.cancel' | translate }}</button>
-    <button type="submit" class="btn btn-secondary" id="community-submit">{{ 'community.edit.submit' | translate }}</button>
-  </div>
-</form>
+<ds-form *ngIf="formModel" #formRef="formComponent"
+         [formId]="'community-form-id'"
+         [formModel]="formModel" (submit)="onSubmit($event)"></ds-form>
+
diff --git a/src/app/+community-page/community-form/community-form.component.ts b/src/app/+community-page/community-form/community-form.component.ts
index d7797028b7cfb339e950fc731a43cf478a81cb2a..fd0b49014661a8be03ebaa8306c9c1b86c608cde 100644
--- a/src/app/+community-page/community-form/community-form.component.ts
+++ b/src/app/+community-page/community-form/community-form.component.ts
@@ -1,39 +1,93 @@
-import { Component, EventEmitter, Output } from '@angular/core';
-import { isNotEmpty } from '../../shared/empty.util';
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
 import { Location } from '@angular/common';
+import {
+  DynamicFormService,
+  DynamicInputModel,
+  DynamicTextAreaModel
+} from '@ng-dynamic-forms/core';
+import { FormGroup } from '@angular/forms';
+import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
+import { Community } from '../../core/shared/community.model';
+import { ResourceType } from '../../core/shared/resource-type';
+import { hasValue, isNotEmpty } from '../../shared/empty.util';
 
 @Component({
   selector: 'ds-community-form',
   styleUrls: ['./community-form.component.scss'],
   templateUrl: './community-form.component.html'
 })
-export class CommunityFormComponent {
+export class CommunityFormComponent implements OnInit {
 
-  name: string;
-  description: string;
-  introductory: string;
-  copyright: string;
-  news: string;
+  @Input() community: Community = new Community();
+  formModel: DynamicFormControlModel[] = [
+    new DynamicInputModel({
+      id: 'title',
+      name: 'dc.title',
+      label: 'Name',
+      required: true,
+      validators: {
+        required: null
+      },
+      errorMessages: {
+        required: 'Please enter a name for this title'
+      }
+    }),
+    new DynamicTextAreaModel({
+      id: 'description',
+      name: 'dc.description',
+      label: 'Introductory text (HTML)',
+    }),
+    new DynamicTextAreaModel({
+      id: 'abstract',
+      name: 'dc.description.abstract',
+      label: 'Short Description',
+    }),
+    new DynamicTextAreaModel({
+      id: 'rights',
+      name: 'dc.rights',
+      label: 'Copyright text (HTML)',
+    }),
+    new DynamicTextAreaModel({
+      id: 'tableofcontents',
+      name: 'dc.description.tableofcontents',
+      label: 'News (HTML)',
+    }),
+  ];
 
-  nameRequiredError = false;
+  formGroup: FormGroup;
 
-  @Output() submitted: EventEmitter<any> = new EventEmitter();
+  @Output() submitForm: EventEmitter<any> = new EventEmitter();
 
-  public constructor(private location: Location) {
+  public constructor(private location: Location, private formService: DynamicFormService) {
+  }
 
+  ngOnInit(): void {
+    this.formModel.forEach(
+      (fieldModel: DynamicInputModel) => {
+        fieldModel.value = this.community.findMetadata(fieldModel.name);
+      }
+    );
+    this.formGroup = this.formService.createFormGroup(this.formModel);
   }
 
-  onSubmit(data: any) {
-    if (isNotEmpty(data.name)) {
-      this.submitted.emit(data);
-      this.nameRequiredError = false;
-    } else {
-      this.nameRequiredError = true;
-    }
+  onSubmit(event: Event) {
+    event.stopPropagation();
+    const metadata = this.formModel.map(
+      (fieldModel: DynamicInputModel) => {
+        return { key: fieldModel.name, value: fieldModel.value }
+      }
+    );
+    const filteredOldMetadata = this.community.metadata.filter((filter) => !metadata.map((md) => md.key).includes(filter.key));
+    const filteredNewMetadata = metadata.filter((md) => isNotEmpty(md.value));
+    const newMetadata = [...filteredOldMetadata, ...filteredNewMetadata];
+    const updatedCommunity = Object.assign({}, this.community, {
+      metadata: newMetadata,
+      type: ResourceType.Community
+    });
+    this.submitForm.emit(updatedCommunity);
   }
 
   cancel() {
     this.location.back();
   }
-
 }
diff --git a/src/app/+community-page/community-page-routing.module.ts b/src/app/+community-page/community-page-routing.module.ts
index 17889d6e487602a498bc1d83a00d427243bfb2ea..8fcc2cde6f5feb4c41786eeb49ec84b51f228b2c 100644
--- a/src/app/+community-page/community-page-routing.module.ts
+++ b/src/app/+community-page/community-page-routing.module.ts
@@ -5,13 +5,23 @@ import { CommunityPageComponent } from './community-page.component';
 import { CommunityPageResolver } from './community-page.resolver';
 import { CreateCommunityPageComponent } from './create-community-page/create-community-page.component';
 import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
+import { EditCommunityPageComponent } from './edit-community-page/edit-community-page.component';
 
 @NgModule({
   imports: [
     RouterModule.forChild([
       { path: 'create',
         component: CreateCommunityPageComponent,
-        canActivate: [AuthenticatedGuard] },
+        canActivate: [AuthenticatedGuard]
+      },
+      { path: ':id/edit',
+        pathMatch: 'full',
+        component: EditCommunityPageComponent,
+        canActivate: [AuthenticatedGuard],
+        resolve: {
+          community: CommunityPageResolver
+        }
+      },
       {
         path: ':id',
         component: CommunityPageComponent,
diff --git a/src/app/+community-page/community-page.component.html b/src/app/+community-page/community-page.component.html
index 1bf322a68892bb17810697a818e42bbff3aec5ff..52bc9fe928663e0342698568349571bcd8782e79 100644
--- a/src/app/+community-page/community-page.component.html
+++ b/src/app/+community-page/community-page.component.html
@@ -28,6 +28,8 @@
         [community]="communityPayload"></ds-community-page-sub-collection-list>
     </div>
   </div>
+  <a [routerLink]="'edit'">Edit</a>
+
   <ds-error *ngIf="communityRD?.hasFailed" message="{{'error.community' | translate}}"></ds-error>
   <ds-loading *ngIf="communityRD?.isLoading"
               message="{{'loading.community' | translate}}"></ds-loading>
diff --git a/src/app/+community-page/community-page.component.ts b/src/app/+community-page/community-page.component.ts
index ce260aefc018d58d70b4d8fd198f6e06c962af07..bfaac33c1c39f36eeb5eeae510b42d78bc33f049 100644
--- a/src/app/+community-page/community-page.component.ts
+++ b/src/app/+community-page/community-page.component.ts
@@ -24,8 +24,6 @@ import { hasValue } from '../shared/empty.util';
 export class CommunityPageComponent implements OnInit, OnDestroy {
   communityRD$: Observable<RemoteData<Community>>;
   logoRD$: Observable<RemoteData<Bitstream>>;
-
-
   private subs: Subscription[] = [];
 
   constructor(
@@ -42,14 +40,9 @@ export class CommunityPageComponent implements OnInit, OnDestroy {
       map((rd: RemoteData<Community>) => rd.payload),
       filter((community: Community) => hasValue(community)),
       mergeMap((community: Community) => community.logo));
-
-
   }
 
   ngOnDestroy(): void {
     this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
   }
-
-
-
 }
diff --git a/src/app/+community-page/community-page.module.ts b/src/app/+community-page/community-page.module.ts
index 292e6aaf9ca306608d0faadd218c35a13fe9cbaf..23050f40db6d90961d5759db0db9a7e1a828613f 100644
--- a/src/app/+community-page/community-page.module.ts
+++ b/src/app/+community-page/community-page.module.ts
@@ -8,6 +8,7 @@ import { CommunityPageSubCollectionListComponent } from './sub-collection-list/c
 import { CommunityPageRoutingModule } from './community-page-routing.module';
 import { CreateCommunityPageComponent } from './create-community-page/create-community-page.component';
 import { CommunityFormComponent } from './community-form/community-form.component';
+import { EditCommunityPageComponent } from './edit-community-page/edit-community-page.component';
 
 @NgModule({
   imports: [
@@ -19,6 +20,7 @@ import { CommunityFormComponent } from './community-form/community-form.componen
     CommunityPageComponent,
     CommunityPageSubCollectionListComponent,
     CreateCommunityPageComponent,
+    EditCommunityPageComponent,
     CommunityFormComponent
   ]
 })
diff --git a/src/app/+community-page/create-community-page/create-community-page.component.html b/src/app/+community-page/create-community-page/create-community-page.component.html
index 35f1deaa73339731d70a4a239c1d037122e64369..bb0f5b83af30c9db1ea9ec024cd15f447c1daf31 100644
--- a/src/app/+community-page/create-community-page/create-community-page.component.html
+++ b/src/app/+community-page/create-community-page/create-community-page.component.html
@@ -7,5 +7,5 @@
       </ng-container>
     </div>
   </div>
-  <ds-community-form (submitted)="onSubmit($event)"></ds-community-form>
+  <ds-community-form (submitForm)="onSubmit($event)"></ds-community-form>
 </div>
diff --git a/src/app/+community-page/create-community-page/create-community-page.component.spec.ts b/src/app/+community-page/create-community-page/create-community-page.component.spec.ts
index 6c5eb5f59155b3f58b963f7a2e625c71ef41fade..e76b10bde67d984dffef91ac1337e3730ab6cdd8 100644
--- a/src/app/+community-page/create-community-page/create-community-page.component.spec.ts
+++ b/src/app/+community-page/create-community-page/create-community-page.component.spec.ts
@@ -8,12 +8,10 @@ import { Observable } from 'rxjs/Observable';
 import { RemoteData } from '../../core/data/remote-data';
 import { Community } from '../../core/shared/community.model';
 import { DSOSuccessResponse, ErrorResponse } from '../../core/cache/response-cache.models';
-import { BrowserModule } from '@angular/platform-browser';
 import { SharedModule } from '../../shared/shared.module';
 import { CommonModule } from '@angular/common';
 import { CommunityFormComponent } from '../community-form/community-form.component';
 import { RouterTestingModule } from '@angular/router/testing';
-import { RequestError } from '../../core/data/request.models';
 
 describe('CreateCommunityPageComponent', () => {
   let comp: CreateCommunityPageComponent;
diff --git a/src/app/+community-page/create-community-page/create-community-page.component.ts b/src/app/+community-page/create-community-page/create-community-page.component.ts
index 0d97f2402891aba5b17f045e075114a09db41f4b..5373abfe2257f3d5916080f78f66b30db4e36164 100644
--- a/src/app/+community-page/create-community-page/create-community-page.component.ts
+++ b/src/app/+community-page/create-community-page/create-community-page.component.ts
@@ -1,4 +1,4 @@
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
 import { Community } from '../../core/shared/community.model';
 import { CommunityDataService } from '../../core/data/community-data.service';
 import { Observable } from 'rxjs';
@@ -7,55 +7,46 @@ import { Router } from '@angular/router';
 import { RemoteData } from '../../core/data/remote-data';
 import { isNotEmpty } from '../../shared/empty.util';
 import { DSpaceObject } from '../../core/shared/dspace-object.model';
-import { take } from 'rxjs/operators';
-import { ResourceType } from '../../core/shared/resource-type';
-import { NormalizedCommunity } from '../../core/cache/models/normalized-community.model';
+import { map, take } from 'rxjs/operators';
+import { getSucceededRemoteData } from '../../core/shared/operators';
 
 @Component({
   selector: 'ds-create-community',
   styleUrls: ['./create-community-page.component.scss'],
   templateUrl: './create-community-page.component.html'
 })
-export class CreateCommunityPageComponent {
+export class CreateCommunityPageComponent implements OnInit {
 
   public parentUUID$: Observable<string>;
-  public communityRDObs: Observable<RemoteData<Community>>;
+  public parentRD$: Observable<RemoteData<Community>>;
 
   public constructor(
     private communityDataService: CommunityDataService,
     private routeService: RouteService,
     private router: Router
   ) {
+
+  }
+
+  ngOnInit(): void {
     this.parentUUID$ = this.routeService.getQueryParameterValue('parent');
-    this.parentUUID$.subscribe((uuid: string) => {
-      if (isNotEmpty(uuid)) {
-        this.communityRDObs = this.communityDataService.findById(uuid);
+    this.parentUUID$.subscribe((parentID: string) => {
+      if (isNotEmpty(parentID)) {
+        this.parentRD$ = this.communityDataService.findById(parentID);
       }
     });
   }
 
-  onSubmit(data: any) {
+  onSubmit(community: Community) {
     this.parentUUID$.pipe(take(1)).subscribe((uuid: string) => {
-      const community = Object.assign(new NormalizedCommunity(), {
-        name: data.name,
-        metadata: [
-          { key: 'dc.description', value: data.introductory },
-          { key: 'dc.description.abstract', value: data.description },
-          { key: 'dc.rights', value: data.copyright }
-          // TODO: metadata for news
-        ],
-        type: ResourceType.Community
-      });
-      this.communityDataService.create(community, uuid).pipe(take(1)).subscribe((rd: RemoteData<DSpaceObject>) => {
-        if (rd.hasSucceeded) {
-          if (uuid) {
-            this.router.navigate(['communities', uuid]);
-          } else {
-            this.router.navigate([]);
-          }
-        }
+      this.communityDataService.create(community, uuid)
+        .pipe(getSucceededRemoteData())
+        .subscribe((communityRD: RemoteData<Community>) => {
+          const newUUID = communityRD.payload.uuid;
+          this.router.navigate(['/communities/' + newUUID]);
       });
     });
   }
 
+
 }
diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.html b/src/app/+community-page/edit-community-page/edit-community-page.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..eb9f797b3d88dbd9e3ad088c075fcfa0f1427ef6
--- /dev/null
+++ b/src/app/+community-page/edit-community-page/edit-community-page.component.html
@@ -0,0 +1,11 @@
+<div class="container">
+  <div class="row">
+    <div class="col-12 pb-4">
+      <ng-container *ngVar="(parentUUID$ | async)?.payload as parent">
+        <h2 *ngIf="!parent" id="header" class="border-bottom pb-2">{{ 'community.edit.head' | translate }}</h2>
+        <h2 *ngIf="parent" id="sub-header" class="border-bottom pb-2">{{ 'community.edit.sub-head' | translate:{ parent: parent.name } }}</h2>
+      </ng-container>
+    </div>
+  </div>
+  <ds-community-form (submitForm)="onSubmit($event)" [community]="(communityRD$ | async)?.payload"></ds-community-form>
+</div>
diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.scss b/src/app/+community-page/edit-community-page/edit-community-page.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/src/app/+community-page/edit-community-page/edit-community-page.component.scss
@@ -0,0 +1 @@
+
diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts b/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6c5eb5f59155b3f58b963f7a2e625c71ef41fade
--- /dev/null
+++ b/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts
@@ -0,0 +1,90 @@
+import { CreateCommunityPageComponent } from './create-community-page.component';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { CommunityDataService } from '../../core/data/community-data.service';
+import { RouteService } from '../../shared/services/route.service';
+import { Router } from '@angular/router';
+import { TranslateModule } from '@ngx-translate/core';
+import { Observable } from 'rxjs/Observable';
+import { RemoteData } from '../../core/data/remote-data';
+import { Community } from '../../core/shared/community.model';
+import { DSOSuccessResponse, ErrorResponse } from '../../core/cache/response-cache.models';
+import { BrowserModule } from '@angular/platform-browser';
+import { SharedModule } from '../../shared/shared.module';
+import { CommonModule } from '@angular/common';
+import { CommunityFormComponent } from '../community-form/community-form.component';
+import { RouterTestingModule } from '@angular/router/testing';
+import { RequestError } from '../../core/data/request.models';
+
+describe('CreateCommunityPageComponent', () => {
+  let comp: CreateCommunityPageComponent;
+  let fixture: ComponentFixture<CreateCommunityPageComponent>;
+  let communityDataService: CommunityDataService;
+  let routeService: RouteService;
+  let router: Router;
+
+  const community = Object.assign(new Community(), {
+    uuid: 'a20da287-e174-466a-9926-f66b9300d347',
+    name: 'test community'
+  });
+
+  const newCommunity = Object.assign(new Community(), {
+    uuid: '1ff59938-a69a-4e62-b9a4-718569c55d48',
+    name: 'new community'
+  });
+
+  const communityDataServiceStub = {
+    findById: (uuid) => Observable.of(new RemoteData(false, false, true, null, Object.assign(new Community(), {
+      uuid: uuid,
+      name: community.name
+    }))),
+    create: (com, uuid?) => Observable.of(new RemoteData(false, false, true, undefined, newCommunity))
+  };
+  const routeServiceStub = {
+    getQueryParameterValue: (param) => Observable.of(community.uuid)
+  };
+  const routerStub = {
+    navigate: (commands) => commands
+  };
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
+      declarations: [CreateCommunityPageComponent, CommunityFormComponent],
+      providers: [
+        { provide: CommunityDataService, useValue: communityDataServiceStub },
+        { provide: RouteService, useValue: routeServiceStub },
+        { provide: Router, useValue: routerStub }
+      ]
+    }).compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(CreateCommunityPageComponent);
+    comp = fixture.componentInstance;
+    fixture.detectChanges();
+    communityDataService = (comp as any).communityDataService;
+    routeService = (comp as any).routeService;
+    router = (comp as any).router;
+  });
+
+  describe('onSubmit', () => {
+    const data = {
+      name: 'test'
+    };
+
+    it('should navigate when successful', () => {
+      spyOn(router, 'navigate');
+      comp.onSubmit(data);
+      fixture.detectChanges();
+      expect(router.navigate).toHaveBeenCalled();
+    });
+
+    it('should not navigate on failure', () => {
+      spyOn(router, 'navigate');
+      spyOn(communityDataService, 'create').and.returnValue(Observable.of(new RemoteData(true, true, false, undefined, newCommunity)));
+      comp.onSubmit(data);
+      fixture.detectChanges();
+      expect(router.navigate).not.toHaveBeenCalled();
+    });
+  });
+});
diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.ts b/src/app/+community-page/edit-community-page/edit-community-page.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..58805af80acd1b28bdd26ad60051062147582716
--- /dev/null
+++ b/src/app/+community-page/edit-community-page/edit-community-page.component.ts
@@ -0,0 +1,46 @@
+import { Component } from '@angular/core';
+import { Community } from '../../core/shared/community.model';
+import { CommunityDataService } from '../../core/data/community-data.service';
+import { Observable } from 'rxjs';
+import { RouteService } from '../../shared/services/route.service';
+import { ActivatedRoute, Router } from '@angular/router';
+import { RemoteData } from '../../core/data/remote-data';
+import { isNotEmpty } from '../../shared/empty.util';
+import { DSpaceObject } from '../../core/shared/dspace-object.model';
+import { first, map, take, tap } from 'rxjs/operators';
+import { ResourceType } from '../../core/shared/resource-type';
+import { NormalizedCommunity } from '../../core/cache/models/normalized-community.model';
+import { getSucceededRemoteData } from '../../core/shared/operators';
+
+@Component({
+  selector: 'ds-edit-community',
+  styleUrls: ['./edit-community-page.component.scss'],
+  templateUrl: './edit-community-page.component.html'
+})
+export class EditCommunityPageComponent {
+
+  public parentUUID$: Observable<string>;
+  public parentRD$: Observable<RemoteData<Community>>;
+  public communityRD$: Observable<RemoteData<Community>>;
+
+  public constructor(
+    private communityDataService: CommunityDataService,
+    private routeService: RouteService,
+    private router: Router,
+    private route: ActivatedRoute
+  ) {
+  }
+
+  ngOnInit(): void {
+    this.communityRD$ = this.route.data.pipe(first(), map((data) => data.community));
+  }
+
+  onSubmit(community: Community) {
+    this.communityDataService.update(community)
+      .pipe(getSucceededRemoteData())
+      .subscribe((communityRD: RemoteData<Community>) => {
+        const newUUID = communityRD.payload.uuid;
+        this.router.navigate(['/communities/' + newUUID]);
+      });
+  }
+}
diff --git a/src/app/core/cache/builders/data-build.service.ts b/src/app/core/cache/builders/data-build.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8ba3ebee0c75e13575e089037a557835ad089b84
--- /dev/null
+++ b/src/app/core/cache/builders/data-build.service.ts
@@ -0,0 +1,36 @@
+import { Injectable } from '@angular/core';
+import { NormalizedObject } from '../models/normalized-object.model';
+import { CacheableObject } from '../object-cache.reducer';
+import { getRelationships } from './build-decorators';
+import { NormalizedObjectFactory } from '../models/normalized-object-factory';
+import { map, take } from 'rxjs/operators';
+import { hasValue, isNotEmpty } from '../../../shared/empty.util';
+import { PaginatedList } from '../../data/paginated-list';
+
+export function isRestDataObject(halObj: any) {
+  return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
+}
+
+export function isRestPaginatedList(halObj: any) {
+  return hasValue(halObj.page) && hasValue(halObj._embedded);
+}
+
+export function isPaginatedList(halObj: any) {
+  return hasValue(halObj.page) && hasValue(halObj.pageInfo);
+}
+
+@Injectable()
+export class DataBuildService {
+  normalize<TDomain extends CacheableObject, TNormalized extends NormalizedObject>(domainModel: TDomain): TNormalized {
+    const normalizedConstructor = NormalizedObjectFactory.getConstructor(domainModel.type);
+    const relationships = getRelationships(normalizedConstructor) || [];
+
+    const normalizedModel = Object.assign({}, domainModel) as any;
+    relationships.forEach((key: string) => {
+      if (hasValue(domainModel[key])) {
+        domainModel[key] = undefined;
+      }
+    });
+    return normalizedModel;
+  }
+}
diff --git a/src/app/core/cache/builders/remote-data-build.service.ts b/src/app/core/cache/builders/remote-data-build.service.ts
index 1dc255f26e91a3d9a6ab9ba012527260c6942de4..7b51526432dd795f699cdd6bc237a1b799e58812 100644
--- a/src/app/core/cache/builders/remote-data-build.service.ts
+++ b/src/app/core/cache/builders/remote-data-build.service.ts
@@ -51,10 +51,7 @@ export class RemoteDataBuildService {
     const requestEntry$ = observableRace(
       href$.pipe(getRequestFromRequestHref(this.requestService)),
       requestUUID$.pipe(getRequestFromRequestUUID(this.requestService)),
-    ).pipe(
-      take(1)
     );
-
     // always use self link if that is cached, only if it isn't, get it via the response.
     const payload$ =
       observableCombineLatest(
diff --git a/src/app/core/cache/models/normalized-community.model.ts b/src/app/core/cache/models/normalized-community.model.ts
index 4ab2408a53f3fedf25b75c07794b98735d1f4b40..e915d2f50a9175d2baba8e92e5ad47e185eb5d9d 100644
--- a/src/app/core/cache/models/normalized-community.model.ts
+++ b/src/app/core/cache/models/normalized-community.model.ts
@@ -1,4 +1,4 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
+import { autoserialize, deserialize, inheritSerialization, serialize } from 'cerialize';
 
 import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
 import { Community } from '../../shared/community.model';
@@ -21,32 +21,32 @@ export class NormalizedCommunity extends NormalizedDSpaceObject {
   /**
    * The Bitstream that represents the logo of this Community
    */
-  @autoserialize
+  @deserialize
   @relationship(ResourceType.Bitstream, false)
   logo: string;
 
   /**
    * An array of Communities that are direct parents of this Community
    */
-  @autoserialize
+  @deserialize
   @relationship(ResourceType.Community, true)
   parents: string[];
 
   /**
    * The Community that owns this Community
    */
-  @autoserialize
+  @deserialize
   @relationship(ResourceType.Community, false)
   owner: string;
 
   /**
    * List of Collections that are owned by this Community
    */
-  @autoserialize
+  @deserialize
   @relationship(ResourceType.Collection, true)
   collections: string[];
 
-  @autoserialize
+  @deserialize
   @relationship(ResourceType.Community, true)
   subcommunities: string[];
 
diff --git a/src/app/core/cache/models/normalized-dspace-object.model.ts b/src/app/core/cache/models/normalized-dspace-object.model.ts
index 92174c40f778af9aebc62f6f89bb155ab9e054d3..efdfa6dd741a7bd0f9cf76025a759e5f4d645dfb 100644
--- a/src/app/core/cache/models/normalized-dspace-object.model.ts
+++ b/src/app/core/cache/models/normalized-dspace-object.model.ts
@@ -1,4 +1,4 @@
-import { autoserialize, autoserializeAs } from 'cerialize';
+import { autoserialize, autoserializeAs, deserialize, serialize } from 'cerialize';
 import { DSpaceObject } from '../../shared/dspace-object.model';
 
 import { Metadatum } from '../../shared/metadatum.model';
@@ -45,12 +45,6 @@ export class NormalizedDSpaceObject extends NormalizedObject {
   @autoserialize
   type: ResourceType;
 
-  /**
-   * The name for this DSpaceObject
-   */
-  @autoserialize
-  name: string;
-
   /**
    * An array containing all metadata of this DSpaceObject
    */
@@ -60,13 +54,13 @@ export class NormalizedDSpaceObject extends NormalizedObject {
   /**
    * An array of DSpaceObjects that are direct parents of this DSpaceObject
    */
-  @autoserialize
+  @deserialize
   parents: string[];
 
   /**
    * The DSpaceObject that owns this DSpaceObject
    */
-  @autoserialize
+  @deserialize
   owner: string;
 
   /**
@@ -75,7 +69,7 @@ export class NormalizedDSpaceObject extends NormalizedObject {
    * Repeated here to make the serialization work,
    * inheritSerialization doesn't seem to work for more than one level
    */
-  @autoserialize
+  @deserialize
   _links: {
     [name: string]: string
   }
diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts
index dcbdbd00492bec714e15c6011b911e1110bb3048..21917438715ad3b82d43e6295c77e0fb0b42355e 100644
--- a/src/app/core/core.module.ts
+++ b/src/app/core/core.module.ts
@@ -63,6 +63,8 @@ import { NotificationsService } from '../shared/notifications/notifications.serv
 import { UploaderService } from '../shared/uploader/uploader.service';
 import { BrowseItemsResponseParsingService } from './data/browse-items-response-parsing-service';
 import { DSpaceObjectDataService } from './data/dspace-object-data.service';
+import { DataBuildService } from './cache/builders/data-build.service';
+import { DSOUpdateComparator } from './data/dso-update-comparator';
 
 const IMPORTS = [
   CommonModule,
@@ -99,6 +101,7 @@ const PROVIDERS = [
   ObjectCacheService,
   PaginationComponentOptions,
   RegistryService,
+  DataBuildService,
   RemoteDataBuildService,
   RequestService,
   EndpointMapResponseParsingService,
@@ -126,6 +129,7 @@ const PROVIDERS = [
   UploaderService,
   UUIDService,
   DSpaceObjectDataService,
+  DSOUpdateComparator,
   // register AuthInterceptor as HttpInterceptor
   {
     provide: HTTP_INTERCEPTORS,
diff --git a/src/app/core/data/base-response-parsing.service.ts b/src/app/core/data/base-response-parsing.service.ts
index eada156ce9392a66b842d5609f8e683fe893c1a0..d5c1c58296c08c6a552edd89e04474a3c26d34e0 100644
--- a/src/app/core/data/base-response-parsing.service.ts
+++ b/src/app/core/data/base-response-parsing.service.ts
@@ -8,15 +8,7 @@ import { GenericConstructor } from '../shared/generic-constructor';
 import { PaginatedList } from './paginated-list';
 import { ResourceType } from '../shared/resource-type';
 import { RESTURLCombiner } from '../url-combiner/rest-url-combiner';
-
-function isObjectLevel(halObj: any) {
-  return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
-}
-
-function isPaginatedResponse(halObj: any) {
-  return hasValue(halObj.page) && hasValue(halObj._embedded);
-}
-
+import { isRestDataObject, isRestPaginatedList } from '../cache/builders/data-build.service';
 /* tslint:disable:max-classes-per-file */
 
 export abstract class BaseResponseParsingService {
@@ -29,11 +21,11 @@ export abstract class BaseResponseParsingService {
     if (isNotEmpty(data)) {
       if (hasNoValue(data) || (typeof data !== 'object')) {
         return data;
-      } else if (isPaginatedResponse(data)) {
+      } else if (isRestPaginatedList(data)) {
         return this.processPaginatedList(data, requestUUID);
       } else if (Array.isArray(data)) {
         return this.processArray(data, requestUUID);
-      } else if (isObjectLevel(data)) {
+      } else if (isRestDataObject(data)) {
         data = this.fixBadEPersonRestResponse(data);
         const object = this.deserialize(data);
         if (isNotEmpty(data._embedded)) {
@@ -43,10 +35,10 @@ export abstract class BaseResponseParsingService {
             .forEach((property) => {
               const parsedObj = this.process<ObjectDomain, ObjectType>(data._embedded[property], requestUUID);
               if (isNotEmpty(parsedObj)) {
-                if (isPaginatedResponse(data._embedded[property])) {
+                if (isRestPaginatedList(data._embedded[property])) {
                   object[property] = parsedObj;
                   object[property].page = parsedObj.page.map((obj) => obj.self);
-                } else if (isObjectLevel(data._embedded[property])) {
+                } else if (isRestDataObject(data._embedded[property])) {
                   object[property] = parsedObj.self;
                 } else if (Array.isArray(parsedObj)) {
                   object[property] = parsedObj.map((obj) => obj.self)
@@ -80,7 +72,7 @@ export abstract class BaseResponseParsingService {
       list = this.flattenSingleKeyObject(list);
     }
     const page: ObjectDomain[] = this.processArray(list, requestUUID);
-    return new PaginatedList<ObjectDomain>(pageInfo, page);
+    return new PaginatedList<ObjectDomain>(pageInfo, page, );
   }
 
   protected processArray<ObjectDomain, ObjectType>(data: any, requestUUID: string): ObjectDomain[] {
diff --git a/src/app/core/data/collection-data.service.ts b/src/app/core/data/collection-data.service.ts
index b936d71c3053822284c91a9f806186b09152eff0..ef294c1296048ccfb8d0224b9cad8a19477a58ee 100644
--- a/src/app/core/data/collection-data.service.ts
+++ b/src/app/core/data/collection-data.service.ts
@@ -1,4 +1,4 @@
-import { Inject, Injectable } from '@angular/core';
+import { Injectable } from '@angular/core';
 import { Store } from '@ngrx/store';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { NormalizedCollection } from '../cache/models/normalized-collection.model';
@@ -10,9 +10,10 @@ import { CommunityDataService } from './community-data.service';
 import { RequestService } from './request.service';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { AuthService } from '../auth/auth.service';
-import { Community } from '../shared/community.model';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { HttpClient } from '@angular/common/http';
+import { DataBuildService } from '../cache/builders/data-build.service';
+import { DSOUpdateComparator } from './dso-update-comparator';
 
 @Injectable()
 export class CollectionDataService extends ComColDataService<NormalizedCollection, Collection> {
@@ -21,13 +22,15 @@ export class CollectionDataService extends ComColDataService<NormalizedCollectio
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
+    protected dataBuildService: DataBuildService,
     protected store: Store<CoreState>,
     protected cds: CommunityDataService,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
     protected authService: AuthService,
     protected notificationsService: NotificationsService,
-    protected http: HttpClient
+    protected http: HttpClient,
+    protected comparator: DSOUpdateComparator
   ) {
     super();
   }
diff --git a/src/app/core/data/comcol-data.service.spec.ts b/src/app/core/data/comcol-data.service.spec.ts
index 3325dc6ac3fdfbf6adff9d0702876a0dc69b033a..0bf5f857498301f3114708b832d27f88a5a4d29b 100644
--- a/src/app/core/data/comcol-data.service.spec.ts
+++ b/src/app/core/data/comcol-data.service.spec.ts
@@ -14,10 +14,12 @@ import { NormalizedObject } from '../cache/models/normalized-object.model';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { RequestEntry } from './request.reducer';
 import { of as observableOf } from 'rxjs';
-import { Community } from '../shared/community.model';
 import { AuthService } from '../auth/auth.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { HttpClient } from '@angular/common/http';
+import { DataBuildService } from '../cache/builders/data-build.service';
+import { DSOUpdateComparator } from './dso-update-comparator';
+import { UpdateComparator } from './update-comparator';
 
 const LINK_NAME = 'test';
 
@@ -30,6 +32,7 @@ class TestService extends ComColDataService<NormalizedTestObject, any> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
+    protected dataBuildService: DataBuildService,
     protected store: Store<CoreState>,
     protected EnvConfig: GlobalConfig,
     protected cds: CommunityDataService,
@@ -38,6 +41,7 @@ class TestService extends ComColDataService<NormalizedTestObject, any> {
     protected authService: AuthService,
     protected notificationsService: NotificationsService,
     protected http: HttpClient,
+    protected comparator: DSOUpdateComparator,
     protected linkPath: string
   ) {
     super();
@@ -60,6 +64,8 @@ describe('ComColDataService', () => {
   const EnvConfig = {} as GlobalConfig;
   const notificationsService = {} as NotificationsService;
   const http = {} as HttpClient;
+  const comparator = {} as any;
+  const dataBuildService = {} as DataBuildService;
 
   const scopeID = 'd9d30c0c-69b7-4369-8397-ca67c888974d';
   const options = Object.assign(new FindAllOptions(), {
@@ -78,7 +84,7 @@ describe('ComColDataService', () => {
   const authHeader = 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJlaWQiOiJhNjA4NmIzNC0zOTE4LTQ1YjctOGRkZC05MzI5YTcwMmEyNmEiLCJzZyI6W10sImV4cCI6MTUzNDk0MDcyNX0.RV5GAtiX6cpwBN77P_v16iG9ipeyiO7faNYSNMzq_sQ';
 
   const mockHalService = {
-    getEndpoint: (linkPath) => Observable.of(communitiesEndpoint)
+    getEndpoint: (linkPath) => observableOf(communitiesEndpoint)
   };
 
   function initMockCommunityDataService(): CommunityDataService {
@@ -112,6 +118,7 @@ describe('ComColDataService', () => {
     return new TestService(
       requestService,
       rdbService,
+      dataBuildService,
       store,
       EnvConfig,
       cds,
@@ -120,6 +127,7 @@ describe('ComColDataService', () => {
       authService,
       notificationsService,
       http,
+      comparator,
       LINK_NAME
     );
   }
diff --git a/src/app/core/data/comcol-data.service.ts b/src/app/core/data/comcol-data.service.ts
index d3eed88ffd43741fc7adf1993bba10ffa3a640ad..0616e9c2edc0f732a321145fd86125ce3c2b66de 100644
--- a/src/app/core/data/comcol-data.service.ts
+++ b/src/app/core/data/comcol-data.service.ts
@@ -20,8 +20,9 @@ import { NormalizedObject } from '../cache/models/normalized-object.model';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { RequestEntry } from './request.reducer';
 import { getResponseFromEntry } from '../shared/operators';
+import { CacheableObject } from '../cache/object-cache.reducer';
 
-export abstract class ComColDataService<TNormalized extends NormalizedObject, TDomain> extends DataService<TNormalized, TDomain> {
+export abstract class ComColDataService<TNormalized extends NormalizedObject, TDomain extends CacheableObject> extends DataService<TNormalized, TDomain> {
   protected abstract cds: CommunityDataService;
   protected abstract objectCache: ObjectCacheService;
   protected abstract halService: HALEndpointService;
diff --git a/src/app/core/data/community-data.service.ts b/src/app/core/data/community-data.service.ts
index 9645a970c67bdb07a8089d6ee1861e2512da5261..40d433a2455708b72461ccf794a90716958995a0 100644
--- a/src/app/core/data/community-data.service.ts
+++ b/src/app/core/data/community-data.service.ts
@@ -18,6 +18,8 @@ import { Observable } from 'rxjs';
 import { PaginatedList } from './paginated-list';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { HttpClient } from '@angular/common/http';
+import { DataBuildService } from '../cache/builders/data-build.service';
+import { DSOUpdateComparator } from './dso-update-comparator';
 
 @Injectable()
 export class CommunityDataService extends ComColDataService<NormalizedCommunity, Community> {
@@ -28,12 +30,14 @@ export class CommunityDataService extends ComColDataService<NormalizedCommunity,
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
+    protected dataBuildService: DataBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
     protected authService: AuthService,
     protected notificationsService: NotificationsService,
-    protected http: HttpClient
+    protected http: HttpClient,
+    protected comparator: DSOUpdateComparator
   ) {
     super();
   }
diff --git a/src/app/core/data/config-response-parsing.service.spec.ts b/src/app/core/data/config-response-parsing.service.spec.ts
index a33c5cf5b5c685d5ba5ce03f6ec275e94f1a3595..caf8ef4a192805cbc304e89fcff509c704d24059 100644
--- a/src/app/core/data/config-response-parsing.service.spec.ts
+++ b/src/app/core/data/config-response-parsing.service.spec.ts
@@ -177,7 +177,7 @@ describe('ConfigResponseParsingService', () => {
           'https://rest.api/config/submissionsections/traditionalpagetwo',
           'https://rest.api/config/submissionsections/upload',
           'https://rest.api/config/submissionsections/license'
-        ])
+        ], 'https://rest.api/config/submissiondefinitions/traditional/sections')
       });
 
     it('should return a ConfigSuccessResponse if data contains a valid config endpoint response', () => {
diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts
index 4bbe775f3b572cc21ce12da296ee019b10065b33..85d65791767f2d9a0c7c5502927dfeb6ad8354bd 100644
--- a/src/app/core/data/data.service.ts
+++ b/src/app/core/data/data.service.ts
@@ -1,4 +1,13 @@
-import { delay, distinctUntilChanged, filter, find, switchMap, map, take, tap } from 'rxjs/operators';
+import {
+  delay,
+  distinctUntilChanged,
+  filter,
+  find,
+  switchMap,
+  map,
+  take,
+  tap, first, mergeMap
+} from 'rxjs/operators';
 import { Observable } from 'rxjs';
 import { Store } from '@ngrx/store';
 import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
@@ -32,10 +41,14 @@ import { DSOSuccessResponse, ErrorResponse, RestResponse } from '../cache/respon
 import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
 import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
 import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
+import { CacheableObject } from '../cache/object-cache.reducer';
+import { DataBuildService } from '../cache/builders/data-build.service';
+import { UpdateComparator } from './update-comparator';
 
-export abstract class DataService<TNormalized extends NormalizedObject, TDomain> {
+export abstract class DataService<TNormalized extends NormalizedObject, TDomain extends CacheableObject> {
   protected abstract requestService: RequestService;
   protected abstract rdbService: RemoteDataBuildService;
+  protected abstract dataBuildService: DataBuildService;
   protected abstract store: Store<CoreState>;
   protected abstract linkPath: string;
   protected abstract halService: HALEndpointService;
@@ -43,6 +56,7 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
   protected abstract authService: AuthService;
   protected abstract notificationsService: NotificationsService;
   protected abstract http: HttpClient;
+  protected abstract comparator: UpdateComparator<TNormalized>;
 
   public abstract getBrowseEndpoint(options: FindAllOptions, linkPath?: string): Observable<string>
 
@@ -122,15 +136,21 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
    * The patch is derived from the differences between the given object and its version in the object cache
    * @param {DSpaceObject} object The given object
    */
-  update(object: DSpaceObject) {
-    const oldVersion = this.objectCache.getBySelfLink(object.self);
-    const operations = compare(oldVersion, object);
-    if (isNotEmpty(operations)) {
-      this.objectCache.addPatch(object.self, operations);
-    }
+  update(object: TDomain): Observable<RemoteData<TDomain>> {
+    const oldVersion$ = this.objectCache.getBySelfLink(object.self);
+    return oldVersion$.pipe(first(), mergeMap((oldVersion: TNormalized) => {
+        const newVersion = this.dataBuildService.normalize<TDomain, TNormalized>(object);
+        const operations = this.comparator.compare(oldVersion, newVersion);
+        if (isNotEmpty(operations)) {
+          this.objectCache.addPatch(object.self, operations);
+        }
+        return this.findById(object.uuid);
+      }
+    ));
+
   }
 
-  create(dso: TNormalized, parentUUID: string): Observable<RemoteData<TDomain>> {
+  create(dso: TDomain, parentUUID: string): Observable<RemoteData<TDomain>> {
     const requestId = this.requestService.generateRequestId();
     const endpoint$ = this.halService.getEndpoint(this.linkPath).pipe(
       isNotEmptyOperator(),
@@ -138,7 +158,8 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
       map((endpoint: string) => parentUUID ? `${endpoint}?parent=${parentUUID}` : endpoint)
     );
 
-    const serializedDso = new DSpaceRESTv2Serializer(NormalizedObjectFactory.getConstructor(dso.type)).serialize(dso);
+    const normalizedObject: TNormalized = this.dataBuildService.normalize<TDomain, TNormalized>(dso);
+    const serializedDso = new DSpaceRESTv2Serializer(NormalizedObjectFactory.getConstructor(dso.type)).serialize(normalizedObject);
 
     const request$ = endpoint$.pipe(
       take(1),
@@ -150,6 +171,7 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
       configureRequest(this.requestService)
     ).subscribe();
 
+    // Resolve self link for new object
     const selfLink$ = this.requestService.getByUUID(requestId).pipe(
       getResponseFromEntry(),
       map((response: RestResponse) => {
diff --git a/src/app/core/data/dso-update-comparator.ts b/src/app/core/data/dso-update-comparator.ts
new file mode 100644
index 0000000000000000000000000000000000000000..245fbfaef0273aa3d1302e7a61d7633455d97bf0
--- /dev/null
+++ b/src/app/core/data/dso-update-comparator.ts
@@ -0,0 +1,12 @@
+import { Operation } from 'fast-json-patch/lib/core';
+import { compare } from 'fast-json-patch';
+import { UpdateComparator } from './update-comparator';
+import { NormalizedDSpaceObject } from '../cache/models/normalized-dspace-object.model';
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class DSOUpdateComparator implements UpdateComparator<NormalizedDSpaceObject> {
+  compare(object1: NormalizedDSpaceObject, object2: NormalizedDSpaceObject): Operation[] {
+    return compare(object1.metadata, object2.metadata).map((operation: Operation) => Object.assign({}, operation, { path: '/metadata' + operation.path }));
+  }
+}
diff --git a/src/app/core/data/dspace-object-data.service.ts b/src/app/core/data/dspace-object-data.service.ts
index 3e8d8bdc04ec423a03928261ecf68cead1e44f57..f1d0f217629b1bf0591b6907996dfe55a94c35f7 100644
--- a/src/app/core/data/dspace-object-data.service.ts
+++ b/src/app/core/data/dspace-object-data.service.ts
@@ -14,6 +14,8 @@ import { ObjectCacheService } from '../cache/object-cache.service';
 import { AuthService } from '../auth/auth.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { HttpClient } from '@angular/common/http';
+import { DataBuildService } from '../cache/builders/data-build.service';
+import { DSOUpdateComparator } from './dso-update-comparator';
 
 /* tslint:disable:max-classes-per-file */
 class DataServiceImpl extends DataService<NormalizedDSpaceObject, DSpaceObject> {
@@ -22,12 +24,14 @@ class DataServiceImpl extends DataService<NormalizedDSpaceObject, DSpaceObject>
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
+    protected dataBuildService: DataBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
     protected authService: AuthService,
     protected notificationsService: NotificationsService,
-    protected http: HttpClient) {
+    protected http: HttpClient,
+    protected comparator: DSOUpdateComparator) {
     super();
   }
 
@@ -48,12 +52,14 @@ export class DSpaceObjectDataService {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
+    protected dataBuildService: DataBuildService,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
     protected authService: AuthService,
     protected notificationsService: NotificationsService,
-    protected http: HttpClient) {
-    this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, authService, notificationsService, http);
+    protected http: HttpClient,
+    protected comparator: DSOUpdateComparator) {
+    this.dataService = new DataServiceImpl(requestService, rdbService, dataBuildService, null, objectCache, halService, authService, notificationsService, http, comparator);
   }
 
   findById(uuid: string): Observable<RemoteData<DSpaceObject>> {
diff --git a/src/app/core/data/item-data.service.ts b/src/app/core/data/item-data.service.ts
index 68380ddaa25a60d6bb7e8f9c979e11eef58dd605..411daa9b356e4103375b99b5cec5d94925e03647 100644
--- a/src/app/core/data/item-data.service.ts
+++ b/src/app/core/data/item-data.service.ts
@@ -19,6 +19,8 @@ import { ObjectCacheService } from '../cache/object-cache.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { AuthService } from '../auth/auth.service';
 import { HttpClient } from '@angular/common/http';
+import { DataBuildService } from '../cache/builders/data-build.service';
+import { DSOUpdateComparator } from './dso-update-comparator';
 
 @Injectable()
 export class ItemDataService extends DataService<NormalizedItem, Item> {
@@ -27,13 +29,15 @@ export class ItemDataService extends DataService<NormalizedItem, Item> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
+    protected dataBuildService: DataBuildService,
     protected store: Store<CoreState>,
     private bs: BrowseService,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
     protected authService: AuthService,
     protected notificationsService: NotificationsService,
-    protected http: HttpClient) {
+    protected http: HttpClient,
+    protected comparator: DSOUpdateComparator) {
     super();
   }
 
diff --git a/src/app/core/data/paginated-list.ts b/src/app/core/data/paginated-list.ts
index 07d53739d0f9582ed1cfe8739b846d8618a1be1b..8efdccd75d55a77cd15ef531976b87d1ce1dd3f8 100644
--- a/src/app/core/data/paginated-list.ts
+++ b/src/app/core/data/paginated-list.ts
@@ -81,4 +81,12 @@ export class PaginatedList<T> {
   set last(last: string) {
     this.pageInfo.last = last;
   }
+
+  get self(): string {
+    return this.pageInfo.self;
+  }
+
+  set self(self: string) {
+    this.pageInfo.self = self;
+  }
 }
diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts
index 285ed065454390879f8ce11441386477d8b677bf..20bc85a87ffbe30241454be3e040f4bf5661ca7f 100644
--- a/src/app/core/data/request.service.ts
+++ b/src/app/core/data/request.service.ts
@@ -80,7 +80,7 @@ export class RequestService {
       this.store.pipe(select(this.entryFromUUIDSelector(uuid))),
       this.store.pipe(
         select(this.originalUUIDFromUUIDSelector(uuid)),
-        switchMap((originalUUID) => {
+        mergeMap((originalUUID) => {
             return this.store.pipe(select(this.entryFromUUIDSelector(originalUUID)))
           },
         ))
diff --git a/src/app/core/data/update-comparator.ts b/src/app/core/data/update-comparator.ts
new file mode 100644
index 0000000000000000000000000000000000000000..884ac585f54647811abb9dcec71ad37c575535d5
--- /dev/null
+++ b/src/app/core/data/update-comparator.ts
@@ -0,0 +1,6 @@
+import { NormalizedObject } from '../cache/models/normalized-object.model';
+import { Operation } from 'fast-json-patch/lib/core';
+
+export interface UpdateComparator<TNormalized extends NormalizedObject> {
+  compare(object1: TNormalized, object2: TNormalized):  Operation[];
+}
\ No newline at end of file
diff --git a/src/app/core/shared/dspace-object.model.ts b/src/app/core/shared/dspace-object.model.ts
index 68338143ba0cad5e0b5e800a585c12a1fe67cfef..3e08da151cead2f5f8ab26ea3c56f84820dec2df 100644
--- a/src/app/core/shared/dspace-object.model.ts
+++ b/src/app/core/shared/dspace-object.model.ts
@@ -34,14 +34,15 @@ export class DSpaceObject implements CacheableObject, ListableObject {
   /**
    * The name for this DSpaceObject
    */
-  @autoserialize
-  name: string;
+  get name(): string {
+    return this.findMetadata('dc.title');
+  }
 
   /**
    * An array containing all metadata of this DSpaceObject
    */
   @autoserialize
-  metadata: Metadatum[];
+  metadata: Metadatum[] = [];
 
   /**
    * An array of DSpaceObjects that are direct parents of this DSpaceObject
diff --git a/src/app/core/shared/page-info.model.ts b/src/app/core/shared/page-info.model.ts
index ba2af24dce33e16b746ce40598abe5788f1a837e..4ed281657d2b3ed9c0b7608799215e4e06760d9b 100644
--- a/src/app/core/shared/page-info.model.ts
+++ b/src/app/core/shared/page-info.model.ts
@@ -39,4 +39,7 @@ export class PageInfo {
 
   @autoserialize
   first: string;
+
+  @autoserialize
+  self: string;
 }
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts
index 3544bce280081f36a37efa576d3712a6eace55ea..8a3cf52abbce14c68aff9372af86b52e08605481 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts
@@ -96,7 +96,6 @@ export class DsDynamicFormControlComponent extends DynamicFormControlContainerCo
   }
 
   static getFormControlType(model: DynamicFormControlModel): Type<DynamicFormControl> | null {
-
     switch (model.type) {
 
       case DYNAMIC_FORM_CONTROL_TYPE_ARRAY:
diff --git a/src/app/shared/form/form.component.html b/src/app/shared/form/form.component.html
index 958c9a6c73cd4edd4e7c30582f13d55004a59daa..18d6533df4fddfed983fa97283524c1118facd12 100644
--- a/src/app/shared/form/form.component.html
+++ b/src/app/shared/form/form.component.html
@@ -51,7 +51,7 @@
 
         <div class="col text-right">
           <button type="reset" class="btn btn-default" (click)="reset()">{{'form.cancel' | translate}}</button>
-          <button type="submit" class="btn btn-primary" (click)="onSubmit($event)"
+          <button type="submit" class="btn btn-primary" (click)="onSubmit()"
                   [disabled]="!(isValid() | async)">{{'form.submit' | translate}}
           </button>
         </div>
diff --git a/src/app/shared/form/form.component.ts b/src/app/shared/form/form.component.ts
index 2d74ddf8d4e75c07ce2d76f053b4232d07d2c0e6..9848f9feedc437c49bd46931061fb639c8eb8473 100644
--- a/src/app/shared/form/form.component.ts
+++ b/src/app/shared/form/form.component.ts
@@ -73,7 +73,7 @@ export class FormComponent implements OnDestroy, OnInit {
    * An event fired when form is valid and submitted .
    * Event's payload equals to the form content.
    */
-  @Output() submit: EventEmitter<Observable<any>> = new EventEmitter<Observable<any>>();
+  @Output() submitForm: EventEmitter<Observable<any>> = new EventEmitter<Observable<any>>();
 
   /**
    * An object of FormGroup type
@@ -264,7 +264,7 @@ export class FormComponent implements OnDestroy, OnInit {
    */
   onSubmit(): void {
     if (this.getFormGroupValidStatus()) {
-      this.submit.emit(this.formService.getFormData(this.formId));
+      this.submitForm.emit(this.formService.getFormData(this.formId));
     } else {
       this.formService.validateAllFormFields(this.formGroup);
     }
diff --git a/src/app/shared/form/form.service.ts b/src/app/shared/form/form.service.ts
index ae5ba9f278ca079803469e7512de031ecb4a6cf4..9356f86e8cf5faadc1c0c69cf0260f670a6ef277 100644
--- a/src/app/shared/form/form.service.ts
+++ b/src/app/shared/form/form.service.ts
@@ -98,7 +98,7 @@ export class FormService {
     const errorKey = this.getValidatorNameFromMap(message);
     let errorMsg = message;
 
-    // if form control model has not errorMessages object, create it
+    // if form control model has no errorMessages object, create it
     if (!model.errorMessages) {
       model.errorMessages = {};
     }