diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..5889e7a85c0d4d2e5e97b5e010d9070bfc386c56
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,21 @@
+.git
+node-modules
+__build__
+__server_build__
+typings
+tsd_typings
+npm-debug.log
+dist
+coverage
+.idea
+*.iml
+*.ngfactory.ts
+*.css.shim.ts
+*.scss.shim.ts
+.DS_Store
+webpack.records.json
+npm-debug.log.*
+morgan.log
+yarn-error.log
+*.css
+package-lock.json
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..f10164ebd034a85b7525ef8ab7a150348064867c
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,10 @@
+# This image will be published as dspace/dspace-angular
+# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
+
+FROM node:8-alpine
+WORKDIR /app
+ADD . /app/
+EXPOSE 3000
+
+RUN yarn install
+CMD yarn run watch
diff --git a/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.html b/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.html
index b04e93ff71036aefffac430568b89b7759803123..12c2578d9ceb6cc855f027a47e4e9842ac85818f 100644
--- a/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.html
+++ b/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.html
@@ -2,7 +2,7 @@
   <div *ngIf="subCollectionsRD?.hasSucceeded" @fadeIn>
     <h2>{{'community.sub-collection-list.head' | translate}}</h2>
     <ul>
-      <li *ngFor="let collection of subCollectionsRD?.payload">
+      <li *ngFor="let collection of subCollectionsRD?.payload.page">
         <p>
           <span class="lead"><a [routerLink]="['/collections', collection.id]">{{collection.name}}</a></span><br>
           <span class="text-muted">{{collection.shortDescription}}</span>
diff --git a/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.ts b/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.ts
index fc697198963c0f341cc10133b44308e0e0349c83..aed2b69a306d486c55f0d8e89535efbbd0f33907 100644
--- a/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.ts
+++ b/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.ts
@@ -6,6 +6,7 @@ import { Collection } from '../../core/shared/collection.model';
 import { Community } from '../../core/shared/community.model';
 
 import { fadeIn } from '../../shared/animations/fade';
+import { PaginatedList } from '../../core/data/paginated-list';
 
 @Component({
   selector: 'ds-community-page-sub-collection-list',
@@ -15,7 +16,7 @@ import { fadeIn } from '../../shared/animations/fade';
 })
 export class CommunityPageSubCollectionListComponent implements OnInit {
   @Input() community: Community;
-  subCollectionsRDObs: Observable<RemoteData<Collection[]>>;
+  subCollectionsRDObs: Observable<RemoteData<PaginatedList<Collection>>>;
 
   ngOnInit(): void {
     this.subCollectionsRDObs = this.community.collections;
diff --git a/src/app/+item-page/field-components/collections/collections.component.html b/src/app/+item-page/field-components/collections/collections.component.html
index bb7ab63341bcce738d6fae63459c1aa77d6394f9..6e5f9a350cdba2846a0f9a20aebce38bae6baac9 100644
--- a/src/app/+item-page/field-components/collections/collections.component.html
+++ b/src/app/+item-page/field-components/collections/collections.component.html
@@ -1,4 +1,4 @@
-<ds-metadata-field-wrapper [label]="label | translate">
+<ds-metadata-field-wrapper *ngIf="hasSucceeded() | async" [label]="label | translate">
     <div class="collections">
         <a *ngFor="let collection of (collections | async); let last=last;" [routerLink]="['/collections', collection.id]">
             <span>{{collection?.name}}</span><span *ngIf="!last" [innerHTML]="separator"></span>
diff --git a/src/app/+item-page/field-components/collections/collections.component.spec.ts b/src/app/+item-page/field-components/collections/collections.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..871018a9d843149b7b83fb7a794821a6f3d7e4e7
--- /dev/null
+++ b/src/app/+item-page/field-components/collections/collections.component.spec.ts
@@ -0,0 +1,74 @@
+import { CollectionsComponent } from './collections.component';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { Collection } from '../../../core/shared/collection.model';
+import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
+import { getMockRemoteDataBuildService } from '../../../shared/mocks/mock-remote-data-build.service';
+import { Item } from '../../../core/shared/item.model';
+import { Observable } from 'rxjs/Observable';
+import { RemoteData } from '../../../core/data/remote-data';
+import { TranslateModule } from '@ngx-translate/core';
+
+let collectionsComponent: CollectionsComponent;
+let fixture: ComponentFixture<CollectionsComponent>;
+
+const mockCollection1: Collection = Object.assign(new Collection(), {
+  metadata: [
+    {
+      key: 'dc.description.abstract',
+      language: 'en_US',
+      value: 'Short description'
+    }]
+});
+
+const succeededMockItem: Item = Object.assign(new Item(), {owningCollection: Observable.of(new RemoteData(false, false, true, null, mockCollection1))});
+const failedMockItem: Item = Object.assign(new Item(), {owningCollection: Observable.of(new RemoteData(false, false, false, null, mockCollection1))});
+
+describe('CollectionsComponent', () => {
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      imports: [TranslateModule.forRoot()],
+      declarations: [ CollectionsComponent ],
+      providers: [
+        { provide: RemoteDataBuildService, useValue: getMockRemoteDataBuildService()}
+      ],
+
+      schemas: [ NO_ERRORS_SCHEMA ]
+    }).overrideComponent(CollectionsComponent, {
+      set: { changeDetection: ChangeDetectionStrategy.Default }
+    }).compileComponents();
+  }));
+
+  beforeEach(async(() => {
+    fixture = TestBed.createComponent(CollectionsComponent);
+    collectionsComponent = fixture.componentInstance;
+    collectionsComponent.label = 'test.test';
+    collectionsComponent.separator = '<br/>';
+
+  }));
+
+  describe('When the requested item request has succeeded', () => {
+    beforeEach(() => {
+      collectionsComponent.item = succeededMockItem;
+      fixture.detectChanges();
+    });
+
+    it('should show the collection', () => {
+      const collectionField = fixture.debugElement.query(By.css('ds-metadata-field-wrapper div.collections'));
+      expect(collectionField).not.toBeNull();
+    });
+  });
+
+  describe('When the requested item request has failed', () => {
+    beforeEach(() => {
+      collectionsComponent.item = failedMockItem;
+      fixture.detectChanges();
+    });
+
+    it('should not show the collection', () => {
+      const collectionField = fixture.debugElement.query(By.css('ds-metadata-field-wrapper div.collections'));
+      expect(collectionField).toBeNull();
+    });
+  });
+});
diff --git a/src/app/+item-page/field-components/collections/collections.component.ts b/src/app/+item-page/field-components/collections/collections.component.ts
index 8b7b5d7f58122fb1fa67c65a4ab253af73de8729..83bb0d464d4d0f78e44c2d8cd485d26e8830157e 100644
--- a/src/app/+item-page/field-components/collections/collections.component.ts
+++ b/src/app/+item-page/field-components/collections/collections.component.ts
@@ -38,4 +38,8 @@ export class CollectionsComponent implements OnInit {
     this.collections = this.item.owner.map((rd: RemoteData<Collection>) => [rd.payload]);
   }
 
+  hasSucceeded() {
+    return this.item.owner.map((rd: RemoteData<Collection>) => rd.hasSucceeded);
+  }
+
 }
diff --git a/src/app/+search-page/paginated-search-options.model.ts b/src/app/+search-page/paginated-search-options.model.ts
index 0c403af827c54ace7cc00a102e7ac9f909b3e280..4f04480391527a0108d36241e305ecc806b8beea 100644
--- a/src/app/+search-page/paginated-search-options.model.ts
+++ b/src/app/+search-page/paginated-search-options.model.ts
@@ -1,7 +1,6 @@
 import { SortOptions } from '../core/cache/models/sort-options.model';
 import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
 import { isNotEmpty } from '../shared/empty.util';
-import { URLCombiner } from '../core/url-combiner/url-combiner';
 import { SearchOptions } from './search-options.model';
 
 export class PaginatedSearchOptions extends SearchOptions {
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 d576b9ea3299786051fa22e3265d71d03cc7ebb0..d934f60e486f24a7471106d4e1ccee4da43c6ae5 100644
--- a/src/app/core/cache/builders/remote-data-build.service.ts
+++ b/src/app/core/cache/builders/remote-data-build.service.ts
@@ -8,12 +8,14 @@ import { RemoteDataError } from '../../data/remote-data-error';
 import { GetRequest } from '../../data/request.models';
 import { RequestEntry } from '../../data/request.reducer';
 import { RequestService } from '../../data/request.service';
+
 import { NormalizedObject } from '../models/normalized-object.model';
 import { ObjectCacheService } from '../object-cache.service';
 import { DSOSuccessResponse, ErrorResponse } from '../response-cache.models';
 import { ResponseCacheEntry } from '../response-cache.reducer';
 import { ResponseCacheService } from '../response-cache.service';
 import { getMapsTo, getRelationMetadata, getRelationships } from './build-decorators';
+import { PageInfo } from '../../shared/page-info.model';
 import {
   getRequestFromSelflink,
   getResourceLinksFromResponse,
@@ -96,7 +98,6 @@ export class RemoteDataBuildService {
             error = new RemoteDataError(resEntry.response.statusCode, errorMessage);
           }
         }
-
         return new RemoteData(
           requestPending,
           responsePending,
@@ -107,7 +108,7 @@ export class RemoteDataBuildService {
       });
   }
 
-  buildList<TNormalized extends NormalizedObject, TDomain>(href$: string | Observable<string>): Observable<RemoteData<TDomain[] | PaginatedList<TDomain>>> {
+  buildList<TNormalized extends NormalizedObject, TDomain>(href$: string | Observable<string>): Observable<RemoteData<PaginatedList<TDomain>>> {
     if (typeof href$ === 'string') {
       href$ = Observable.of(href$);
     }
@@ -144,11 +145,7 @@ export class RemoteDataBuildService {
   );
 
     const payload$ = Observable.combineLatest(tDomainList$, pageInfo$, (tDomainList, pageInfo) => {
-      if (hasValue(pageInfo)) {
-        return new PaginatedList(pageInfo, tDomainList);
-      } else {
-        return tDomainList;
-      }
+      return new PaginatedList(pageInfo, tDomainList);
     });
 
     return this.toRemoteDataObservable(requestEntry$, responseCache$, payload$);
@@ -160,35 +157,43 @@ export class RemoteDataBuildService {
     const relationships = getRelationships(normalized.constructor) || [];
 
     relationships.forEach((relationship: string) => {
+      let result;
       if (hasValue(normalized[relationship])) {
         const { resourceType, isList } = getRelationMetadata(normalized, relationship);
-        if (Array.isArray(normalized[relationship])) {
-          normalized[relationship].forEach((href: string) => {
+        const objectList = normalized[relationship].page || normalized[relationship];
+        if (typeof objectList !== 'string') {
+          objectList.forEach((href: string) => {
             this.requestService.configure(new GetRequest(this.requestService.generateRequestId(), href))
           });
 
           const rdArr = [];
-          normalized[relationship].forEach((href: string) => {
+          objectList.forEach((href: string) => {
             rdArr.push(this.buildSingle(href));
           });
 
           if (isList) {
-            links[relationship] = this.aggregate(rdArr);
+            result = this.aggregate(rdArr);
           } else if (rdArr.length === 1) {
-            links[relationship] = rdArr[0];
+            result = rdArr[0];
           }
         } else {
-          this.requestService.configure(new GetRequest(this.requestService.generateRequestId(), normalized[relationship]));
+          this.requestService.configure(new GetRequest(this.requestService.generateRequestId(), objectList));
 
           // The rest API can return a single URL to represent a list of resources (e.g. /items/:id/bitstreams)
           // in that case only 1 href will be stored in the normalized obj (so the isArray above fails),
           // but it should still be built as a list
           if (isList) {
-            links[relationship] = this.buildList(normalized[relationship]);
+            result = this.buildList(objectList);
           } else {
-            links[relationship] = this.buildSingle(normalized[relationship]);
+            result = this.buildSingle(objectList);
           }
         }
+
+        if (hasValue(normalized[relationship].page)) {
+          links[relationship] = this.aggregatePaginatedList(result, normalized[relationship].pageInfo);
+        } else {
+          links[relationship] = result;
+        }
       }
     });
 
@@ -249,4 +254,8 @@ export class RemoteDataBuildService {
       })
   }
 
+  aggregatePaginatedList<T>(input: Observable<RemoteData<T[]>>, pageInfo: PageInfo): Observable<RemoteData<PaginatedList<T>>> {
+    return input.map((rd) => Object.assign(rd, {payload: new PaginatedList(pageInfo, rd.payload)}));
+  }
+
 }
diff --git a/src/app/core/cache/id-to-uuid-serializer.spec.ts b/src/app/core/cache/id-to-uuid-serializer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e7f6929dddeef6a82104ae12b8eec0b5004479d5
--- /dev/null
+++ b/src/app/core/cache/id-to-uuid-serializer.spec.ts
@@ -0,0 +1,34 @@
+import { IDToUUIDSerializer } from './id-to-uuid-serializer';
+
+describe('IDToUUIDSerializer', () => {
+  let serializer: IDToUUIDSerializer;
+  const prefix = 'test-prefix';
+
+  beforeEach(() => {
+    serializer = new IDToUUIDSerializer(prefix);
+  });
+
+  describe('Serialize', () => {
+    it('should return undefined', () => {
+      expect(serializer.Serialize('some-uuid')).toBeUndefined()
+    });
+  });
+
+  describe('Deserialize', () => {
+    describe('when ID is defined', () => {
+      it('should prepend the prefix to the ID', () => {
+        const id = 'some-id';
+        expect(serializer.Deserialize(id)).toBe(`${prefix}-${id}`);
+      });
+    });
+
+    describe('when ID is null or undefined', () => {
+      it('should return null or undefined', () => {
+        expect(serializer.Deserialize(null)).toBeNull();
+        expect(serializer.Deserialize(undefined)).toBeUndefined();
+      });
+    });
+
+  });
+
+});
diff --git a/src/app/core/cache/id-to-uuid-serializer.ts b/src/app/core/cache/id-to-uuid-serializer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..79576d448e2ae867936dcdf50d1e10d839c48548
--- /dev/null
+++ b/src/app/core/cache/id-to-uuid-serializer.ts
@@ -0,0 +1,35 @@
+import { hasValue } from '../../shared/empty.util';
+
+/**
+ * Serializer to create unique fake UUID's from id's that might otherwise be the same across multiple object types
+ */
+export class IDToUUIDSerializer {
+  /**
+   * @param {string} prefix To prepend the original ID with
+   */
+  constructor(private prefix: string) {
+  }
+
+  /**
+   * Method to serialize a UUID
+   * @param {string} uuid
+   * @returns {any} undefined Fake UUID's should not be sent back to the server, but only be used in the UI
+   */
+  Serialize(uuid: string): any {
+    return undefined;
+  }
+
+  /**
+   * Method to deserialize a UUID
+   * @param {string} id Identifier to transform in to a UUID
+   * @returns {string} UUID based on the prefix and the given id
+   */
+  Deserialize(id: string): string {
+    if (hasValue(id)) {
+      return `${this.prefix}-${id}`;
+    } else {
+      return id;
+    }
+
+  }
+}
diff --git a/src/app/core/cache/models/action-type.model.ts b/src/app/core/cache/models/action-type.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4965f93e8935d2c871c29c0fe6403ff3ad23ce58
--- /dev/null
+++ b/src/app/core/cache/models/action-type.model.ts
@@ -0,0 +1,64 @@
+/**
+ * Enum representing the Action Type of a Resource Policy
+ */
+export enum ActionType {
+  /**
+   * Action of reading, viewing or downloading something
+   */
+  READ = 0,
+
+  /**
+   * Action of modifying something
+   */
+  WRITE = 1,
+
+  /**
+   * Action of deleting something
+   */
+  DELETE = 2,
+
+  /**
+   * Action of adding something to a container
+   */
+  ADD = 3,
+
+  /**
+   * Action of removing something from a container
+   */
+  REMOVE = 4,
+
+  /**
+   * Action of performing workflow step 1
+   */
+  WORKFLOW_STEP_1 = 5,
+
+  /**
+   * Action of performing workflow step 2
+   */
+  WORKFLOW_STEP_2 = 6,
+
+  /**
+   *  Action of performing workflow step 3
+   */
+  WORKFLOW_STEP_3 = 7,
+
+  /**
+   *  Action of performing a workflow abort
+   */
+  WORKFLOW_ABORT = 8,
+
+  /**
+   * Default Read policies for Bitstreams submitted to container
+   */
+  DEFAULT_BITSTREAM_READ = 9,
+
+  /**
+   *  Default Read policies for Items submitted to container
+   */
+  DEFAULT_ITEM_READ = 10,
+
+  /**
+   * Administrative actions
+   */
+  ADMIN = 11,
+}
diff --git a/src/app/core/cache/models/normalized-bitstream-format.model.ts b/src/app/core/cache/models/normalized-bitstream-format.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5d11c97107661f46a58b1135b1c2d263945179e0
--- /dev/null
+++ b/src/app/core/cache/models/normalized-bitstream-format.model.ts
@@ -0,0 +1,66 @@
+import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
+import { BitstreamFormat } from '../../shared/bitstream-format.model';
+
+import { mapsTo } from '../builders/build-decorators';
+import { IDToUUIDSerializer } from '../id-to-uuid-serializer';
+import { NormalizedObject } from './normalized-object.model';
+import { SupportLevel } from './support-level.model';
+
+/**
+ * Normalized model class for a Bitstream Format
+ */
+@mapsTo(BitstreamFormat)
+@inheritSerialization(NormalizedObject)
+export class NormalizedBitstreamFormat extends NormalizedObject {
+
+  /**
+   * Short description of this Bitstream Format
+   */
+  @autoserialize
+  shortDescription: string;
+
+  /**
+   * Description of this Bitstream Format
+   */
+  @autoserialize
+  description: string;
+
+  /**
+   * String representing the MIME type of this Bitstream Format
+   */
+  @autoserialize
+  mimetype: string;
+
+  /**
+   * The level of support the system offers for this Bitstream Format
+   */
+  @autoserialize
+  supportLevel: SupportLevel;
+
+  /**
+   * True if the Bitstream Format is used to store system information, rather than the content of items in the system
+   */
+  @autoserialize
+  internal: boolean;
+
+  /**
+   * String representing this Bitstream Format's file extension
+   */
+  @autoserialize
+  extensions: string;
+
+  /**
+   * Identifier for this Bitstream Format
+   * Note that this ID is unique for bitstream formats,
+   * but might not be unique across different object types
+   */
+  @autoserialize
+  id: string;
+
+  /**
+   * Universally unique identifier for this Bitstream Format
+   * Consist of a prefix and the id field to ensure the identifier is unique across all object types
+   */
+  @autoserializeAs(new IDToUUIDSerializer('bitstream-format'), 'id')
+  uuid: string;
+}
diff --git a/src/app/core/cache/models/normalized-bitstream.model.ts b/src/app/core/cache/models/normalized-bitstream.model.ts
index db8002a87432121a400bfac0482a363aea6e2505..63f84add41b29cdea28d4bfce13befb0c76b5ec9 100644
--- a/src/app/core/cache/models/normalized-bitstream.model.ts
+++ b/src/app/core/cache/models/normalized-bitstream.model.ts
@@ -5,6 +5,9 @@ import { Bitstream } from '../../shared/bitstream.model';
 import { mapsTo, relationship } from '../builders/build-decorators';
 import { ResourceType } from '../../shared/resource-type';
 
+/**
+ * Normalized model class for a DSpace Bitstream
+ */
 @mapsTo(Bitstream)
 @inheritSerialization(NormalizedDSpaceObject)
 export class NormalizedBitstream extends NormalizedDSpaceObject {
diff --git a/src/app/core/cache/models/normalized-bundle.model.ts b/src/app/core/cache/models/normalized-bundle.model.ts
index 3b594dd30856ebad6a2e0cbffded72a80eef1b58..5535ab57e5df13161109b50ed5869e369a0a7a04 100644
--- a/src/app/core/cache/models/normalized-bundle.model.ts
+++ b/src/app/core/cache/models/normalized-bundle.model.ts
@@ -5,6 +5,9 @@ import { Bundle } from '../../shared/bundle.model';
 import { mapsTo, relationship } from '../builders/build-decorators';
 import { ResourceType } from '../../shared/resource-type';
 
+/**
+ * Normalized model class for a DSpace Bundle
+ */
 @mapsTo(Bundle)
 @inheritSerialization(NormalizedDSpaceObject)
 export class NormalizedBundle extends NormalizedDSpaceObject {
@@ -25,6 +28,9 @@ export class NormalizedBundle extends NormalizedDSpaceObject {
    */
   owner: string;
 
+  /**
+   * List of Bitstreams that are part of this Bundle
+   */
   @autoserialize
   @relationship(ResourceType.Bitstream, true)
   bitstreams: string[];
diff --git a/src/app/core/cache/models/normalized-collection.model.ts b/src/app/core/cache/models/normalized-collection.model.ts
index 22e0d20eaad54c53ac0a1897653903a79eca03ab..a2c634c3e5a67161b1cb2bfb074c8c800c7b5634 100644
--- a/src/app/core/cache/models/normalized-collection.model.ts
+++ b/src/app/core/cache/models/normalized-collection.model.ts
@@ -1,10 +1,13 @@
-import { autoserialize, inheritSerialization, autoserializeAs } from 'cerialize';
+import { autoserialize, inheritSerialization } from 'cerialize';
 
 import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
 import { Collection } from '../../shared/collection.model';
 import { mapsTo, relationship } from '../builders/build-decorators';
 import { ResourceType } from '../../shared/resource-type';
 
+/**
+ * Normalized model class for a DSpace Collection
+ */
 @mapsTo(Collection)
 @inheritSerialization(NormalizedDSpaceObject)
 export class NormalizedCollection extends NormalizedDSpaceObject {
@@ -36,6 +39,9 @@ export class NormalizedCollection extends NormalizedDSpaceObject {
   @relationship(ResourceType.Community, false)
   owner: string;
 
+  /**
+   * List of Items that are part of (not necessarily owned by) this Collection
+   */
   @autoserialize
   @relationship(ResourceType.Item, true)
   items: string[];
diff --git a/src/app/core/cache/models/normalized-community.model.ts b/src/app/core/cache/models/normalized-community.model.ts
index 03784e414b07246e69e032f46f7ecb630ba7ad46..b1c2fe3cdde75757ed0d124c0f903b6fb2f794c5 100644
--- a/src/app/core/cache/models/normalized-community.model.ts
+++ b/src/app/core/cache/models/normalized-community.model.ts
@@ -1,10 +1,13 @@
-import { autoserialize, inheritSerialization, autoserializeAs } from 'cerialize';
+import { autoserialize, inheritSerialization } from 'cerialize';
 
 import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
 import { Community } from '../../shared/community.model';
 import { mapsTo, relationship } from '../builders/build-decorators';
 import { ResourceType } from '../../shared/resource-type';
 
+/**
+ * Normalized model class for a DSpace Community
+ */
 @mapsTo(Community)
 @inheritSerialization(NormalizedDSpaceObject)
 export class NormalizedCommunity extends NormalizedDSpaceObject {
@@ -36,6 +39,9 @@ export class NormalizedCommunity extends NormalizedDSpaceObject {
   @relationship(ResourceType.Community, false)
   owner: string;
 
+  /**
+   * List of Collections that are owned by this Community
+   */
   @autoserialize
   @relationship(ResourceType.Collection, true)
   collections: string[];
diff --git a/src/app/core/cache/models/normalized-item.model.ts b/src/app/core/cache/models/normalized-item.model.ts
index a4a14e424c8ccd487552c9f93418bf5e50d33e2e..7d518bd0485f7736bda2323ee6663a3f025c1f3c 100644
--- a/src/app/core/cache/models/normalized-item.model.ts
+++ b/src/app/core/cache/models/normalized-item.model.ts
@@ -5,6 +5,9 @@ import { Item } from '../../shared/item.model';
 import { mapsTo, relationship } from '../builders/build-decorators';
 import { ResourceType } from '../../shared/resource-type';
 
+/**
+ * Normalized model class for a DSpace Item
+ */
 @mapsTo(Item)
 @inheritSerialization(NormalizedDSpaceObject)
 export class NormalizedItem extends NormalizedDSpaceObject {
@@ -49,9 +52,13 @@ export class NormalizedItem extends NormalizedDSpaceObject {
   /**
    * The Collection that owns this Item
    */
+  @autoserialize
   @relationship(ResourceType.Collection, false)
   owningCollection: string;
 
+  /**
+   * List of Bitstreams that are owned by this Item
+   */
   @autoserialize
   @relationship(ResourceType.Bitstream, true)
   bitstreams: string[];
diff --git a/src/app/core/cache/models/normalized-object-factory.ts b/src/app/core/cache/models/normalized-object-factory.ts
index 5b13d55ac80bd5883a9ed4bc125744c8ba91137c..df67a1f2ce78e044fc216808e336c04414449c24 100644
--- a/src/app/core/cache/models/normalized-object-factory.ts
+++ b/src/app/core/cache/models/normalized-object-factory.ts
@@ -6,6 +6,8 @@ import { GenericConstructor } from '../../shared/generic-constructor';
 import { NormalizedCommunity } from './normalized-community.model';
 import { ResourceType } from '../../shared/resource-type';
 import { NormalizedObject } from './normalized-object.model';
+import { NormalizedBitstreamFormat } from './normalized-bitstream-format.model';
+import { NormalizedResourcePolicy } from './normalized-resource-policy.model';
 
 export class NormalizedObjectFactory {
   public static getConstructor(type: ResourceType): GenericConstructor<NormalizedObject> {
@@ -25,6 +27,12 @@ export class NormalizedObjectFactory {
       case ResourceType.Community: {
         return NormalizedCommunity
       }
+      case ResourceType.BitstreamFormat: {
+        return NormalizedBitstreamFormat
+      }
+      case ResourceType.ResourcePolicy: {
+        return NormalizedResourcePolicy
+      }
       default: {
         return undefined;
       }
diff --git a/src/app/core/cache/models/normalized-resource-policy.model.ts b/src/app/core/cache/models/normalized-resource-policy.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b767ca6491e3bec2ee39ad3423ec57eca29ed553
--- /dev/null
+++ b/src/app/core/cache/models/normalized-resource-policy.model.ts
@@ -0,0 +1,49 @@
+import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
+import { ResourcePolicy } from '../../shared/resource-policy.model';
+
+import { mapsTo, relationship } from '../builders/build-decorators';
+import { NormalizedObject } from './normalized-object.model';
+import { IDToUUIDSerializer } from '../id-to-uuid-serializer';
+import { ResourceType } from '../../shared/resource-type';
+import { ActionType } from './action-type.model';
+
+/**
+ * Normalized model class for a Resource Policy
+ */
+@mapsTo(ResourcePolicy)
+@inheritSerialization(NormalizedObject)
+export class NormalizedResourcePolicy extends NormalizedObject {
+
+  /**
+   * The action that is allowed by this Resource Policy
+   */
+  action: ActionType;
+
+  /**
+   * The name for this Resource Policy
+   */
+  @autoserialize
+  name: string;
+
+  /**
+   * The uuid of the Group this Resource Policy applies to
+   */
+  @relationship(ResourceType.Group, false)
+  @autoserializeAs(String, 'groupUUID')
+  group: string;
+
+  /**
+   * Identifier for this Resource Policy
+   * Note that this ID is unique for resource policies,
+   * but might not be unique across different object types
+   */
+  @autoserialize
+  id: string;
+
+  /**
+   * The universally unique identifier for this Resource Policy
+   * Consist of a prefix and the id field to ensure the identifier is unique across all object types
+   */
+  @autoserializeAs(new IDToUUIDSerializer('resource-policy'), 'id')
+  uuid: string;
+}
diff --git a/src/app/core/cache/models/support-level.model.ts b/src/app/core/cache/models/support-level.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..30f759d55ffa23eeb07fba8469ced22ba116a725
--- /dev/null
+++ b/src/app/core/cache/models/support-level.model.ts
@@ -0,0 +1,19 @@
+/**
+ * Enum representing the Support Level of a Bitstream Format
+ */
+export enum SupportLevel {
+  /**
+   * Unknown for Bitstream Formats that are unknown to the system
+   */
+  Unknown = 0,
+
+  /**
+   * Unknown for Bitstream Formats that are known to the system, but not fully supported
+   */
+  Known = 1,
+
+  /**
+   * Supported for Bitstream Formats that are known to the system and fully supported
+   */
+  Supported = 2,
+}
diff --git a/src/app/core/cache/response-cache.service.spec.ts b/src/app/core/cache/response-cache.service.spec.ts
index 1def7faa02d0a3ddb4ce91ecb6cf32ce51386091..77838b6eb6d4d2c62ba8611cb38749a53fa9ad97 100644
--- a/src/app/core/cache/response-cache.service.spec.ts
+++ b/src/app/core/cache/response-cache.service.spec.ts
@@ -46,7 +46,6 @@ describe('ResponseCacheService', () => {
 
       let testObj: ResponseCacheEntry;
       service.get(keys[1]).first().subscribe((entry) => {
-        console.log(entry);
         testObj = entry;
       });
       expect(testObj.key).toEqual(keys[1]);
diff --git a/src/app/core/data/base-response-parsing.service.ts b/src/app/core/data/base-response-parsing.service.ts
index bde08579460cc2cef3725583eaa2c1d2fd353473..050b3c2da591483f3f2105db0c32d78213d5d4fa 100644
--- a/src/app/core/data/base-response-parsing.service.ts
+++ b/src/app/core/data/base-response-parsing.service.ts
@@ -4,8 +4,9 @@ import { CacheableObject } from '../cache/object-cache.reducer';
 import { PageInfo } from '../shared/page-info.model';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { GlobalConfig } from '../../../config/global-config.interface';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
 import { GenericConstructor } from '../shared/generic-constructor';
+import { PaginatedList } from './paginated-list';
+import { NormalizedObject } from '../cache/models/normalized-object.model';
 
 function isObjectLevel(halObj: any) {
   return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
@@ -17,96 +18,103 @@ function isPaginatedResponse(halObj: any) {
 
 /* tslint:disable:max-classes-per-file */
 
-class ProcessRequestDTO<ObjectDomain> {
-  [key: string]: ObjectDomain[]
-}
-
 export abstract class BaseResponseParsingService {
   protected abstract EnvConfig: GlobalConfig;
   protected abstract objectCache: ObjectCacheService;
   protected abstract objectFactory: any;
   protected abstract toCache: boolean;
 
-  protected process<ObjectDomain,ObjectType>(data: any, requestHref: string): ProcessRequestDTO<ObjectDomain> {
+  protected process<ObjectDomain, ObjectType>(data: any, requestHref: string): any {
 
     if (isNotEmpty(data)) {
-      if (isPaginatedResponse(data)) {
-        return this.process(data._embedded, requestHref);
+      if (hasNoValue(data) || (typeof data !== 'object')) {
+        return data;
+      } else if (isPaginatedResponse(data)) {
+        return this.processPaginatedList(data, requestHref);
+      } else if (Array.isArray(data)) {
+        return this.processArray(data, requestHref);
       } else if (isObjectLevel(data)) {
-        return { topLevel: this.deserializeAndCache(data, requestHref) };
-      } else {
-        const result = new ProcessRequestDTO<ObjectDomain>();
-        if (Array.isArray(data)) {
-          result.topLevel = [];
-          data.forEach((datum) => {
-            if (isPaginatedResponse(datum)) {
-              const obj = this.process(datum, requestHref);
-              result.topLevel = [...result.topLevel, ...this.flattenSingleKeyObject(obj)];
-            } else {
-              result.topLevel = [...result.topLevel, ...this.deserializeAndCache<ObjectDomain,ObjectType>(datum, requestHref)];
-            }
-          });
-        } else {
-          Object.keys(data)
-            .filter((property) => data.hasOwnProperty(property))
-            .filter((property) => hasValue(data[property]))
+        const object = this.deserialize(data);
+        if (isNotEmpty(data._embedded)) {
+          Object
+            .keys(data._embedded)
+            .filter((property) => data._embedded.hasOwnProperty(property))
             .forEach((property) => {
-              if (isPaginatedResponse(data[property])) {
-                const obj = this.process(data[property], requestHref);
-                result[property] = this.flattenSingleKeyObject(obj);
-              } else {
-                result[property] = this.deserializeAndCache(data[property], requestHref);
+              const parsedObj = this.process<ObjectDomain, ObjectType>(data._embedded[property], requestHref);
+              if (isNotEmpty(parsedObj)) {
+                if (isPaginatedResponse(data._embedded[property])) {
+                  object[property] = parsedObj;
+                  object[property].page = parsedObj.page.map((obj) => obj.self);
+                } else if (isObjectLevel(data._embedded[property])) {
+                  object[property] = parsedObj.self;
+                } else if (Array.isArray(parsedObj)) {
+                  object[property] = parsedObj.map((obj) => obj.self)
+                }
               }
             });
         }
-        return result;
+        this.cache(object, requestHref);
+        return object;
       }
+      const result = {};
+      Object.keys(data)
+        .filter((property) => data.hasOwnProperty(property))
+        .filter((property) => hasValue(data[property]))
+        .forEach((property) => {
+          const obj = this.process(data[property], requestHref);
+          result[property] = obj;
+        });
+      return result;
+
     }
   }
 
-  protected deserializeAndCache<ObjectDomain,ObjectType>(obj, requestHref: string): ObjectDomain[] {
-    if (Array.isArray(obj)) {
-      let result = [];
-      obj.forEach((o) => result = [...result, ...this.deserializeAndCache<ObjectDomain,ObjectType>(o, requestHref)]);
-      return result;
+  protected processPaginatedList<ObjectDomain, ObjectType>(data: any, requestHref: string): PaginatedList<ObjectDomain> {
+    const pageInfo: PageInfo = this.processPageInfo(data);
+    let list = data._embedded;
+
+    // Workaround for inconsistency in rest response. Issue: https://github.com/DSpace/dspace-angular/issues/238
+    if (!Array.isArray(list)) {
+      list = this.flattenSingleKeyObject(list);
     }
+    const page: ObjectDomain[] = this.processArray(list, requestHref);
+    return new PaginatedList<ObjectDomain>(pageInfo, page);
+  }
+
+  protected processArray<ObjectDomain, ObjectType>(data: any, requestHref: string): ObjectDomain[] {
+    let array: ObjectDomain[] = [];
+    data.forEach((datum) => {
+        array = [...array, this.process(datum, requestHref)];
+      }
+    );
+    return array;
+  }
 
+  protected deserialize<ObjectDomain, ObjectType>(obj): any {
     const type: ObjectType = obj.type;
     if (hasValue(type)) {
       const normObjConstructor = this.objectFactory.getConstructor(type) as GenericConstructor<ObjectDomain>;
 
       if (hasValue(normObjConstructor)) {
         const serializer = new DSpaceRESTv2Serializer(normObjConstructor);
-
-        let processed;
-        if (isNotEmpty(obj._embedded)) {
-          processed = this.process<ObjectDomain,ObjectType>(obj._embedded, requestHref);
-        }
-        const normalizedObj: any = serializer.deserialize(obj);
-
-        if (isNotEmpty(processed)) {
-          const processedList = {};
-          Object.keys(processed).forEach((key) => {
-            processedList[key] = processed[key].map((no: NormalizedObject) => (this.toCache) ? no.self : no);
-          });
-          Object.assign(normalizedObj, processedList);
-        }
-
-        if (this.toCache) {
-          this.addToObjectCache(normalizedObj, requestHref);
-        }
-        return [normalizedObj] as any;
-
+        const res = serializer.deserialize(obj);
+        return res;
       } else {
         // TODO: move check to Validator?
         // throw new Error(`The server returned an object with an unknown a known type: ${type}`);
-        return [];
+        return null;
       }
 
     } else {
       // TODO: move check to Validator
       // throw new Error(`The server returned an object without a type: ${JSON.stringify(obj)}`);
-      return [];
+      return null;
+    }
+  }
+
+  protected cache<ObjectDomain, ObjectType>(obj, requestHref) {
+    if (this.toCache) {
+      this.addToObjectCache(obj, requestHref);
     }
   }
 
@@ -119,7 +127,7 @@ export abstract class BaseResponseParsingService {
 
   processPageInfo(payload: any): PageInfo {
     if (isNotEmpty(payload.page)) {
-      const pageObj = Object.assign({}, payload.page, {_links: payload._links});
+      const pageObj = Object.assign({}, payload.page, { _links: payload._links });
       const pageInfoObject = new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj);
       if (pageInfoObject.currentPage >= 0) {
         Object.assign(pageInfoObject, { currentPage: pageInfoObject.currentPage + 1 });
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 3a09de6e4c4e69a31637f4cac9d232bee1225fa7..654ee536518c85f268d459c3f10c3d61fc087387 100644
--- a/src/app/core/data/config-response-parsing.service.spec.ts
+++ b/src/app/core/data/config-response-parsing.service.spec.ts
@@ -1,5 +1,4 @@
 import { ConfigSuccessResponse, ErrorResponse } from '../cache/response-cache.models';
-import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
 import { ConfigResponseParsingService } from './config-response-parsing.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { GlobalConfig } from '../../../config/global-config.interface';
@@ -8,7 +7,8 @@ import { ConfigRequest } from './request.models';
 import { Store } from '@ngrx/store';
 import { CoreState } from '../core.reducers';
 import { SubmissionDefinitionsModel } from '../shared/config/config-submission-definitions.model';
-import { SubmissionSectionModel } from '../shared/config/config-submission-section.model';
+import { PaginatedList } from './paginated-list';
+import { PageInfo } from '../shared/page-info.model';
 
 describe('ConfigResponseParsingService', () => {
   let service: ConfigResponseParsingService;
@@ -16,141 +16,143 @@ describe('ConfigResponseParsingService', () => {
   const EnvConfig = {} as GlobalConfig;
   const store = {} as Store<CoreState>;
   const objectCacheService = new ObjectCacheService(store);
-
+  let validResponse;
   beforeEach(() => {
     service = new ConfigResponseParsingService(EnvConfig, objectCacheService);
-  });
-
-  describe('parse', () => {
-    const validRequest = new ConfigRequest('69f375b5-19f4-4453-8c7a-7dc5c55aafbb', 'https://rest.api/config/submissiondefinitions/traditional');
-
-    const validResponse = {
+    validResponse = {
       payload: {
-        id:'traditional',
-        name:'traditional',
-        type:'submissiondefinition',
-        isDefault:true,
-        _links:{
-          sections:{
-            href:'https://rest.api/config/submissiondefinitions/traditional/sections'
-          },self:{
-            href:'https://rest.api/config/submissiondefinitions/traditional'
+        id: 'traditional',
+        name: 'traditional',
+        type: 'submissiondefinition',
+        isDefault: true,
+        _links: {
+          sections: {
+            href: 'https://rest.api/config/submissiondefinitions/traditional/sections'
+          },
+          self: {
+            href: 'https://rest.api/config/submissiondefinitions/traditional'
           }
         },
-        _embedded:{
-          sections:{
-            page:{
-              number:0,
-              size:4,
-              totalPages:1,totalElements:4
+        _embedded: {
+          sections: {
+            page: {
+              number: 0,
+              size: 4,
+              totalPages: 1, totalElements: 4
             },
-            _embedded:[
+            _embedded: [
               {
-                id:'traditionalpageone',header:'submit.progressbar.describe.stepone',
-                mandatory:true,
-                sectionType:'submission-form',
-                visibility:{
-                  main:null,
-                  other:'READONLY'
+                id: 'traditionalpageone', header: 'submit.progressbar.describe.stepone',
+                mandatory: true,
+                sectionType: 'submission-form',
+                visibility: {
+                  main: null,
+                  other: 'READONLY'
                 },
-                type:'submissionsection',
-                _links:{
-                  self:{
-                    href:'https://rest.api/config/submissionsections/traditionalpageone'
+                type: 'submissionsection',
+                _links: {
+                  self: {
+                    href: 'https://rest.api/config/submissionsections/traditionalpageone'
                   },
-                  config:{
-                    href:'https://rest.api/config/submissionforms/traditionalpageone'
+                  config: {
+                    href: 'https://rest.api/config/submissionforms/traditionalpageone'
                   }
                 }
               }, {
-                id:'traditionalpagetwo',
-                header:'submit.progressbar.describe.steptwo',
-                mandatory:true,
-                sectionType:'submission-form',
-                visibility:{
-                  main:null,
-                  other:'READONLY'
+                id: 'traditionalpagetwo',
+                header: 'submit.progressbar.describe.steptwo',
+                mandatory: true,
+                sectionType: 'submission-form',
+                visibility: {
+                  main: null,
+                  other: 'READONLY'
                 },
-                type:'submissionsection',
-                _links:{
-                  self:{
-                    href:'https://rest.api/config/submissionsections/traditionalpagetwo'
+                type: 'submissionsection',
+                _links: {
+                  self: {
+                    href: 'https://rest.api/config/submissionsections/traditionalpagetwo'
                   },
-                  config:{
-                    href:'https://rest.api/config/submissionforms/traditionalpagetwo'
+                  config: {
+                    href: 'https://rest.api/config/submissionforms/traditionalpagetwo'
                   }
                 }
               }, {
-                id:'upload',
-                header:'submit.progressbar.upload',
-                mandatory:false,
-                sectionType:'upload',
-                visibility:{
-                  main:null,
-                  other:'READONLY'
+                id: 'upload',
+                header: 'submit.progressbar.upload',
+                mandatory: false,
+                sectionType: 'upload',
+                visibility: {
+                  main: null,
+                  other: 'READONLY'
                 },
-                type:'submissionsection',
-                _links:{
-                  self:{
-                    href:'https://rest.api/config/submissionsections/upload'
+                type: 'submissionsection',
+                _links: {
+                  self: {
+                    href: 'https://rest.api/config/submissionsections/upload'
                   },
                   config: {
-                    href:'https://rest.api/config/submissionuploads/upload'
+                    href: 'https://rest.api/config/submissionuploads/upload'
                   }
                 }
               }, {
-                id:'license',
-                header:'submit.progressbar.license',
-                mandatory:true,
-                sectionType:'license',
-                visibility:{
-                  main:null,
-                  other:'READONLY'
+                id: 'license',
+                header: 'submit.progressbar.license',
+                mandatory: true,
+                sectionType: 'license',
+                visibility: {
+                  main: null,
+                  other: 'READONLY'
                 },
-                type:'submissionsection',
-                _links:{
-                  self:{
-                    href:'https://rest.api/config/submissionsections/license'
+                type: 'submissionsection',
+                _links: {
+                  self: {
+                    href: 'https://rest.api/config/submissionsections/license'
                   }
                 }
               }
             ],
-            _links:{
-              self:'https://rest.api/config/submissiondefinitions/traditional/sections'
+            _links: {
+              self: {
+                href: 'https://rest.api/config/submissiondefinitions/traditional/sections'
+              }
             }
           }
         }
       },
-      statusCode:'200'
+      statusCode: '200'
     };
+  });
+
+  describe('parse', () => {
+    const validRequest = new ConfigRequest('69f375b5-19f4-4453-8c7a-7dc5c55aafbb', 'https://rest.api/config/submissiondefinitions/traditional');
 
     const invalidResponse1 = {
       payload: {},
-      statusCode:'200'
+      statusCode: '200'
     };
 
     const invalidResponse2 = {
       payload: {
-        id:'traditional',
-        name:'traditional',
-        type:'submissiondefinition',
-        isDefault:true,
-        _links:{},
-        _embedded:{
-          sections:{
-            page:{
-              number:0,
-              size:4,
-              totalPages:1,totalElements:4
+        id: 'traditional',
+        name: 'traditional',
+        type: 'submissiondefinition',
+        isDefault: true,
+        _links: {},
+        _embedded: {
+          sections: {
+            page: {
+              number: 0,
+              size: 4,
+              totalPages: 1, totalElements: 4
             },
-            _embedded:[{},{}],
-            _links:{
-              self:'https://rest.api/config/submissiondefinitions/traditional/sections'
+            _embedded: [{}, {}],
+            _links: {
+              self: 'https://rest.api/config/submissiondefinitions/traditional/sections'
             }
           }
         }
       },
-      statusCode:'200'
+      statusCode: '200'
     };
 
     const invalidResponse3 = {
@@ -159,61 +161,24 @@ describe('ConfigResponseParsingService', () => {
         page: { size: 20, totalElements: 2, totalPages: 1, number: 0 }
       }, statusCode: '500'
     };
-
-    const definitions = [
+    const pageinfo = Object.assign(new PageInfo(), { elementsPerPage: 4, totalElements: 4, totalPages: 1, currentPage: 1 });
+    const definitions =
       Object.assign(new SubmissionDefinitionsModel(), {
         isDefault: true,
         name: 'traditional',
         type: 'submissiondefinition',
-        _links: {},
-        sections: [
-          Object.assign(new SubmissionSectionModel(), {
-            header: 'submit.progressbar.describe.stepone',
-            mandatory: true,
-            sectionType: 'submission-form',
-            visibility:{
-              main:null,
-              other:'READONLY'
-            },
-            type: 'submissionsection',
-            _links: {}
-          }),
-          Object.assign(new SubmissionSectionModel(), {
-            header: 'submit.progressbar.describe.steptwo',
-            mandatory: true,
-            sectionType: 'submission-form',
-            visibility:{
-              main:null,
-              other:'READONLY'
-            },
-            type: 'submissionsection',
-            _links: {}
-          }),
-          Object.assign(new SubmissionSectionModel(), {
-            header: 'submit.progressbar.upload',
-            mandatory: false,
-            sectionType: 'upload',
-            visibility:{
-              main:null,
-              other:'READONLY'
-            },
-            type: 'submissionsection',
-            _links: {}
-          }),
-          Object.assign(new SubmissionSectionModel(), {
-            header: 'submit.progressbar.license',
-            mandatory: true,
-            sectionType: 'license',
-            visibility:{
-              main:null,
-              other:'READONLY'
-            },
-            type: 'submissionsection',
-            _links: {}
-          })
-        ]
-      })
-    ];
+        _links: {
+          sections: 'https://rest.api/config/submissiondefinitions/traditional/sections',
+          self: 'https://rest.api/config/submissiondefinitions/traditional'
+        },
+        self: 'https://rest.api/config/submissiondefinitions/traditional',
+        sections: new PaginatedList(pageinfo, [
+          'https://rest.api/config/submissionsections/traditionalpageone',
+          'https://rest.api/config/submissionsections/traditionalpagetwo',
+          'https://rest.api/config/submissionsections/upload',
+          'https://rest.api/config/submissionsections/license'
+        ])
+      });
 
     it('should return a ConfigSuccessResponse if data contains a valid config endpoint response', () => {
       const response = service.parse(validRequest, validResponse);
diff --git a/src/app/core/data/config-response-parsing.service.ts b/src/app/core/data/config-response-parsing.service.ts
index dfbbfc50c769cda17eeafd1323534fa6b6db255c..2b1b9236256e86211a0e21292b0b25425c79c725 100644
--- a/src/app/core/data/config-response-parsing.service.ts
+++ b/src/app/core/data/config-response-parsing.service.ts
@@ -29,7 +29,7 @@ export class ConfigResponseParsingService extends BaseResponseParsingService imp
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
     if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links) && (data.statusCode === '201' || data.statusCode === '200' || data.statusCode === 'OK')) {
       const configDefinition = this.process<ConfigObject,ConfigType>(data.payload, request.href);
-      return new ConfigSuccessResponse(configDefinition[Object.keys(configDefinition)[0]], data.statusCode, this.processPageInfo(data.payload));
+      return new ConfigSuccessResponse(configDefinition, data.statusCode, this.processPageInfo(data.payload));
     } else {
       return new ErrorResponse(
         Object.assign(
diff --git a/src/app/core/data/data.service.spec.ts b/src/app/core/data/data.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8377afe92e4543aeeff1249ee86fe1b95cbb7365
--- /dev/null
+++ b/src/app/core/data/data.service.spec.ts
@@ -0,0 +1,133 @@
+import { DataService } from './data.service';
+import { NormalizedObject } from '../cache/models/normalized-object.model';
+import { ResponseCacheService } from '../cache/response-cache.service';
+import { RequestService } from './request.service';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { CoreState } from '../core.reducers';
+import { Store } from '@ngrx/store';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { Observable } from 'rxjs/Observable';
+import { FindAllOptions } from './request.models';
+import { SortOptions, SortDirection } from '../cache/models/sort-options.model';
+
+const LINK_NAME = 'test'
+
+// tslint:disable:max-classes-per-file
+class NormalizedTestObject extends NormalizedObject {
+}
+
+class TestService extends DataService<NormalizedTestObject, any> {
+    constructor(
+        protected responseCache: ResponseCacheService,
+        protected requestService: RequestService,
+        protected rdbService: RemoteDataBuildService,
+        protected store: Store<CoreState>,
+        protected linkPath: string,
+        protected halService: HALEndpointService
+    ) {
+        super();
+    }
+
+    public getScopedEndpoint(scope: string): Observable<string> {
+        throw new Error('getScopedEndpoint is abstract in DataService');
+    }
+
+}
+
+describe('DataService', () => {
+    let service: TestService;
+    let options: FindAllOptions;
+    const responseCache = {} as ResponseCacheService;
+    const requestService = {} as RequestService;
+    const halService = {} as HALEndpointService;
+    const rdbService = {} as RemoteDataBuildService;
+    const store = {} as Store<CoreState>;
+    const endpoint = 'https://rest.api/core';
+
+    function initTestService(): TestService {
+        return new TestService(
+            responseCache,
+            requestService,
+            rdbService,
+            store,
+            LINK_NAME,
+            halService
+          );
+    }
+
+    service = initTestService();
+
+    describe('getFindAllHref', () => {
+
+        it('should return an observable with the endpoint', () => {
+            options = {};
+
+            (service as any).getFindAllHref(endpoint).subscribe((value) => {
+                    expect(value).toBe(endpoint);
+                }
+            );
+        });
+
+        // getScopedEndpoint is not implemented in abstract DataService
+        it('should throw error if scopeID provided in options', () => {
+            options = { scopeID: 'somevalue' };
+
+            expect(() => { (service as any).getFindAllHref(endpoint, options) })
+                .toThrowError('getScopedEndpoint is abstract in DataService');
+        });
+
+        it('should include page in href if currentPage provided in options', () => {
+            options = { currentPage: 2 };
+            const expected = `${endpoint}?page=${options.currentPage - 1}`;
+
+            (service as any).getFindAllHref(endpoint, options).subscribe((value) => {
+                expect(value).toBe(expected);
+            });
+        });
+
+        it('should include size in href if elementsPerPage provided in options', () => {
+            options = { elementsPerPage: 5 };
+            const expected = `${endpoint}?size=${options.elementsPerPage}`;
+
+            (service as any).getFindAllHref(endpoint, options).subscribe((value) => {
+                expect(value).toBe(expected);
+            });
+        });
+
+        it('should include sort href if SortOptions provided in options', () => {
+            const sortOptions = new SortOptions('field1', SortDirection.ASC);
+            options = { sort:  sortOptions};
+            const expected = `${endpoint}?sort=${sortOptions.field},${sortOptions.direction}`;
+
+            (service as any).getFindAllHref(endpoint, options).subscribe((value) => {
+                expect(value).toBe(expected);
+            });
+        });
+
+        it('should include startsWith in href if startsWith provided in options', () => {
+            options = { startsWith: 'ab' };
+            const expected = `${endpoint}?startsWith=${options.startsWith}`;
+
+            (service as any).getFindAllHref(endpoint, options).subscribe((value) => {
+                expect(value).toBe(expected);
+            });
+        });
+
+        it('should include all provided options in href', () => {
+            const sortOptions = new SortOptions('field1', SortDirection.DESC)
+            options = {
+                currentPage: 6,
+                elementsPerPage: 10,
+                sort: sortOptions,
+                startsWith: 'ab'
+            }
+            const expected = `${endpoint}?page=${options.currentPage - 1}&size=${options.elementsPerPage}` +
+                `&sort=${sortOptions.field},${sortOptions.direction}&startsWith=${options.startsWith}`;
+
+            (service as any).getFindAllHref(endpoint, options).subscribe((value) => {
+                expect(value).toBe(expected);
+        });
+        })
+    });
+
+});
diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts
index 5c01412ba7e8ebf7176141ea18e8a6a5cda35d4d..81381c5f75d6c1bd625b1db340e39a871882634f 100644
--- a/src/app/core/data/data.service.ts
+++ b/src/app/core/data/data.service.ts
@@ -41,6 +41,10 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
       args.push(`sort=${options.sort.field},${options.sort.direction}`);
     }
 
+    if (hasValue(options.startsWith)) {
+      args.push(`startsWith=${options.startsWith}`);
+    }
+
     if (isNotEmpty(args)) {
       return result.map((href: string) => new URLCombiner(href, `?${args.join('&')}`).toString());
     } else {
diff --git a/src/app/core/data/dso-response-parsing.service.ts b/src/app/core/data/dso-response-parsing.service.ts
index 9651eb3157ca6637fa57deab27a241ceb864316d..aff450781f2079dea115d7c37d36cde10d071ba4 100644
--- a/src/app/core/data/dso-response-parsing.service.ts
+++ b/src/app/core/data/dso-response-parsing.service.ts
@@ -12,6 +12,7 @@ import { RestRequest } from './request.models';
 
 import { ResponseParsingService } from './parsing.service';
 import { BaseResponseParsingService } from './base-response-parsing.service';
+import { hasNoValue, hasValue } from '../../shared/empty.util';
 
 @Injectable()
 export class DSOResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
@@ -27,7 +28,16 @@ export class DSOResponseParsingService extends BaseResponseParsingService implem
 
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
     const processRequestDTO = this.process<NormalizedObject,ResourceType>(data.payload, request.href);
-    const selfLinks = this.flattenSingleKeyObject(processRequestDTO).map((no) => no.self);
+    let objectList = processRequestDTO;
+    if (hasNoValue(processRequestDTO)) {
+      return new DSOSuccessResponse([], data.statusCode, undefined)
+    }
+    if (hasValue(processRequestDTO.page)) {
+      objectList = processRequestDTO.page;
+    } else if (!Array.isArray(processRequestDTO)) {
+      objectList = [processRequestDTO];
+    }
+    const selfLinks = objectList.map((no) => no.self);
     return new DSOSuccessResponse(selfLinks, data.statusCode, this.processPageInfo(data.payload))
   }
 
diff --git a/src/app/core/integration/integration-response-parsing.service.spec.ts b/src/app/core/integration/integration-response-parsing.service.spec.ts
index e2e2f92d5aa6c71e1a9c59b3c506c22b3960cbd3..9c3e5b0344150d58f936dc883c1833dd3fc3907b 100644
--- a/src/app/core/integration/integration-response-parsing.service.spec.ts
+++ b/src/app/core/integration/integration-response-parsing.service.spec.ts
@@ -8,6 +8,8 @@ import { CoreState } from '../core.reducers';
 import { IntegrationResponseParsingService } from './integration-response-parsing.service';
 import { IntegrationRequest } from '../data/request.models';
 import { AuthorityValueModel } from './models/authority-value.model';
+import { PageInfo } from '../shared/page-info.model';
+import { PaginatedList } from '../data/paginated-list';
 
 describe('IntegrationResponseParsingService', () => {
   let service: IntegrationResponseParsingService;
@@ -78,7 +80,7 @@ describe('IntegrationResponseParsingService', () => {
 
         },
         _links: {
-          self: 'https://rest.api/integration/authorities/type/entries'
+          self: { href: 'https://rest.api/integration/authorities/type/entries' }
         }
       },
       statusCode: '200'
@@ -141,39 +143,44 @@ describe('IntegrationResponseParsingService', () => {
       },
       statusCode: '200'
     };
-
-    const definitions = [
-      Object.assign(new AuthorityValueModel(), {
+    const pageinfo = Object.assign(new PageInfo(), { elementsPerPage: 5, totalElements: 5, totalPages: 1, currentPage: 1 });
+    const definitions = new PaginatedList(pageinfo,[
+      Object.assign({}, new AuthorityValueModel(), {
+        type: 'authority',
         display: 'One',
         id: 'One',
-        otherInformation: {},
+        otherInformation: undefined,
         value: 'One'
       }),
-      Object.assign(new AuthorityValueModel(), {
+      Object.assign({}, new AuthorityValueModel(), {
+        type: 'authority',
         display: 'Two',
         id: 'Two',
-        otherInformation: {},
+        otherInformation: undefined,
         value: 'Two'
       }),
-      Object.assign(new AuthorityValueModel(), {
+      Object.assign({}, new AuthorityValueModel(), {
+        type: 'authority',
         display: 'Three',
         id: 'Three',
-        otherInformation: {},
+        otherInformation: undefined,
         value: 'Three'
       }),
-      Object.assign(new AuthorityValueModel(), {
+      Object.assign({}, new AuthorityValueModel(), {
+        type: 'authority',
         display: 'Four',
         id: 'Four',
-        otherInformation: {},
+        otherInformation: undefined,
         value: 'Four'
       }),
-      Object.assign(new AuthorityValueModel(), {
+      Object.assign({}, new AuthorityValueModel(), {
+        type: 'authority',
         display: 'Five',
         id: 'Five',
-        otherInformation: {},
+        otherInformation: undefined,
         value: 'Five'
       })
-    ];
+    ]);
 
     it('should return a IntegrationSuccessResponse if data contains a valid endpoint response', () => {
       const response = service.parse(validRequest, validResponse);
diff --git a/src/app/core/integration/integration-response-parsing.service.ts b/src/app/core/integration/integration-response-parsing.service.ts
index 5d6ce09114a2db7dac026de8ec297fad062a417f..06c6b9620d06706e50ab26e0ac5003fe2d1b7b93 100644
--- a/src/app/core/integration/integration-response-parsing.service.ts
+++ b/src/app/core/integration/integration-response-parsing.service.ts
@@ -33,7 +33,7 @@ export class IntegrationResponseParsingService extends BaseResponseParsingServic
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
     if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links)) {
       const dataDefinition = this.process<IntegrationModel,IntegrationType>(data.payload, request.href);
-      return new IntegrationSuccessResponse(dataDefinition[Object.keys(dataDefinition)[0]], data.statusCode, this.processPageInfo(data.payload.page));
+      return new IntegrationSuccessResponse(dataDefinition, data.statusCode, this.processPageInfo(data.payload.page));
     } else {
       return new ErrorResponse(
         Object.assign(
diff --git a/src/app/core/shared/bitstream-format.model.ts b/src/app/core/shared/bitstream-format.model.ts
index b85d9e2053dac7fd1c4387a4219d613bb7cc8534..9af345e6074f6f64c48cdb9b520042aaf2868ad5 100644
--- a/src/app/core/shared/bitstream-format.model.ts
+++ b/src/app/core/shared/bitstream-format.model.ts
@@ -1,24 +1,55 @@
 
-import { autoserialize } from 'cerialize';
+import { CacheableObject } from '../cache/object-cache.reducer';
+import { ResourceType } from './resource-type';
 
-export class BitstreamFormat {
+/**
+ * Model class for a Bitstream Format
+ */
+export class BitstreamFormat implements CacheableObject {
 
-  @autoserialize
+  /**
+   * Short description of this Bitstream Format
+   */
   shortDescription: string;
 
-  @autoserialize
+  /**
+   * Description of this Bitstream Format
+   */
   description: string;
 
-  @autoserialize
+  /**
+   * String representing the MIME type of this Bitstream Format
+   */
   mimetype: string;
 
-  @autoserialize
+  /**
+   * The level of support the system offers for this Bitstream Format
+   */
   supportLevel: number;
 
-  @autoserialize
+  /**
+   * True if the Bitstream Format is used to store system information, rather than the content of items in the system
+   */
   internal: boolean;
 
-  @autoserialize
+  /**
+   * String representing this Bitstream Format's file extension
+   */
   extensions: string;
 
+  /**
+   * The link to the rest endpoint where this Bitstream Format can be found
+   */
+  self: string;
+
+  /**
+   * A ResourceType representing the kind of Object of this BitstreamFormat
+   */
+  type: ResourceType;
+
+  /**
+   * Universally unique identifier for this Bitstream Format
+   */
+  uuid: string;
+
 }
diff --git a/src/app/core/shared/community.model.ts b/src/app/core/shared/community.model.ts
index c34666b0f06d50eac1340f0563ae9c07e3bc19fa..8fd55d312f055508c790779e2a53e8addb32c26d 100644
--- a/src/app/core/shared/community.model.ts
+++ b/src/app/core/shared/community.model.ts
@@ -3,6 +3,7 @@ import { Bitstream } from './bitstream.model';
 import { Collection } from './collection.model';
 import { RemoteData } from '../data/remote-data';
 import { Observable } from 'rxjs/Observable';
+import { PaginatedList } from '../data/paginated-list';
 
 export class Community extends DSpaceObject {
 
@@ -58,6 +59,6 @@ export class Community extends DSpaceObject {
    */
   owner: Observable<RemoteData<Community>>;
 
-  collections: Observable<RemoteData<Collection[]>>;
+  collections: Observable<RemoteData<PaginatedList<Collection>>>;
 
 }
diff --git a/src/app/core/shared/config/config-submission-definitions.model.ts b/src/app/core/shared/config/config-submission-definitions.model.ts
index 8249d2b118af5a72569134ce16365f70406cdf9c..0247f13944c8bbe9a69a00bbb4aa220f56b03889 100644
--- a/src/app/core/shared/config/config-submission-definitions.model.ts
+++ b/src/app/core/shared/config/config-submission-definitions.model.ts
@@ -1,6 +1,7 @@
 import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
 import { ConfigObject } from './config.model';
 import { SubmissionSectionModel } from './config-submission-section.model';
+import { PaginatedList } from '../../data/paginated-list';
 
 @inheritSerialization(ConfigObject)
 export class SubmissionDefinitionsModel extends ConfigObject {
@@ -9,6 +10,6 @@ export class SubmissionDefinitionsModel extends ConfigObject {
   isDefault: boolean;
 
   @autoserializeAs(SubmissionSectionModel)
-  sections: SubmissionSectionModel[];
+  sections: PaginatedList<SubmissionSectionModel>;
 
 }
diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts
index dd60ad9b01ce9776a8d6550ee8109a2440454eae..cc84694e84707126c404c02c7079fbf15ce9515a 100644
--- a/src/app/core/shared/item.model.ts
+++ b/src/app/core/shared/item.model.ts
@@ -5,6 +5,7 @@ import { Collection } from './collection.model';
 import { RemoteData } from '../data/remote-data';
 import { Bitstream } from './bitstream.model';
 import { hasValue, isNotEmpty } from '../../shared/empty.util';
+import { PaginatedList } from '../data/paginated-list';
 
 export class Item extends DSpaceObject {
 
@@ -47,7 +48,7 @@ export class Item extends DSpaceObject {
     return this.owningCollection;
   }
 
-  bitstreams: Observable<RemoteData<Bitstream[]>>;
+  bitstreams: Observable<RemoteData<PaginatedList<Bitstream>>>;
 
   /**
    * Retrieves the thumbnail of this item
@@ -88,7 +89,7 @@ export class Item extends DSpaceObject {
    */
   getBitstreamsByBundleName(bundleName: string): Observable<Bitstream[]> {
     return this.bitstreams
-      .map((rd: RemoteData<Bitstream[]>) => rd.payload)
+      .map((rd: RemoteData<PaginatedList<Bitstream>>) => rd.payload.page)
       .filter((bitstreams: Bitstream[]) => hasValue(bitstreams))
       .startWith([])
       .map((bitstreams) => {
diff --git a/src/app/core/shared/resource-policy.model.ts b/src/app/core/shared/resource-policy.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cccbea1e892d3e5c264d7cfaa0d79ee2e3104af6
--- /dev/null
+++ b/src/app/core/shared/resource-policy.model.ts
@@ -0,0 +1,40 @@
+import { CacheableObject } from '../cache/object-cache.reducer';
+import { ResourceType } from './resource-type';
+import { Group } from '../eperson/models/group.model';
+import { ActionType } from '../cache/models/action-type.model';
+
+/**
+ * Model class for a Resource Policy
+ */
+export class ResourcePolicy implements CacheableObject {
+  /**
+   * The action that is allowed by this Resource Policy
+   */
+  action: ActionType;
+
+  /**
+   * The name for this Resource Policy
+   */
+  name: string;
+
+  /**
+   * The Group this Resource Policy applies to
+   */
+  group: Group;
+
+  /**
+   * The link to the rest endpoint where this Resource Policy can be found
+   */
+  self: string;
+
+  /**
+   * A ResourceType representing the kind of Object of this ResourcePolicy
+   */
+  type: ResourceType;
+
+  /**
+   * The universally unique identifier for this Resource Policy
+   */
+  uuid: string;
+
+}
diff --git a/src/app/core/shared/resource-type.ts b/src/app/core/shared/resource-type.ts
index b774188f630538e69af8e75cf9fa0795e627787f..71053f628b420960e5d5d2c89cfc94c0af24756e 100644
--- a/src/app/core/shared/resource-type.ts
+++ b/src/app/core/shared/resource-type.ts
@@ -8,4 +8,5 @@ export enum ResourceType {
   Community = 'community',
   Eperson = 'eperson',
   Group = 'group',
+  ResourcePolicy = 'resourcePolicy'
 }
diff --git a/src/app/shared/mocks/mock-item.ts b/src/app/shared/mocks/mock-item.ts
index 81c1fcf26cf93ee8a746b437098b920a22ac2d45..f6dd0be861d996385df1f9eb97c1049eee104e1d 100644
--- a/src/app/shared/mocks/mock-item.ts
+++ b/src/app/shared/mocks/mock-item.ts
@@ -17,78 +17,86 @@ export const MockItem: Item = Object.assign(new Item(), {
     errorMessage: '',
     statusCode: '202',
     pageInfo: {},
-    payload: [
-      {
-        sizeBytes: 10201,
-        content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713/content',
-        format: Observable.of({
-          self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/10',
-          requestPending: false,
-          responsePending: false,
-          isSuccessful: true,
-          errorMessage: '',
-          statusCode: '202',
-          pageInfo: {},
-          payload: {
-            shortDescription: 'Microsoft Word XML',
-            description: 'Microsoft Word XML',
-            mimetype: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-            supportLevel: 0,
-            internal: false,
-            extensions: null,
-            self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/10'
-          }
-        }),
-        bundleName: 'ORIGINAL',
-        self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713',
-        id: 'cf9b0c8e-a1eb-4b65-afd0-567366448713',
-        uuid: 'cf9b0c8e-a1eb-4b65-afd0-567366448713',
-        type: 'bitstream',
-        name: 'test_word.docx',
-        metadata: [
-          {
-            key: 'dc.title',
-            language: null,
-            value: 'test_word.docx'
-          }
-        ]
+    payload: {
+      pageInfo: {
+        elementsPerPage: 20,
+        totalElements: 3,
+        totalPages: 1,
+        currentPage: 2
       },
-      {
-        sizeBytes: 31302,
-        content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28/content',
-        format: Observable.of({
-          self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4',
-          requestPending: false,
-          responsePending: false,
-          isSuccessful: true,
-          errorMessage: '',
-          statusCode: '202',
-          pageInfo: {},
-          payload: {
-            shortDescription: 'Adobe PDF',
-            description: 'Adobe Portable Document Format',
-            mimetype: 'application/pdf',
-            supportLevel: 0,
-            internal: false,
-            extensions: null,
-            self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4'
-          }
-        }),
-        bundleName: 'ORIGINAL',
-        self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28',
-        id: '99b00f3c-1cc6-4689-8158-91965bee6b28',
-        uuid: '99b00f3c-1cc6-4689-8158-91965bee6b28',
-        type: 'bitstream',
-        name: 'test_pdf.pdf',
-        metadata: [
-          {
-            key: 'dc.title',
-            language: null,
-            value: 'test_pdf.pdf'
-          }
-        ]
-      }
-    ]
+      page: [
+        {
+          sizeBytes: 10201,
+          content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713/content',
+          format: Observable.of({
+            self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/10',
+            requestPending: false,
+            responsePending: false,
+            isSuccessful: true,
+            errorMessage: '',
+            statusCode: '202',
+            pageInfo: {},
+            payload: {
+              shortDescription: 'Microsoft Word XML',
+              description: 'Microsoft Word XML',
+              mimetype: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+              supportLevel: 0,
+              internal: false,
+              extensions: null,
+              self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/10'
+            }
+          }),
+          bundleName: 'ORIGINAL',
+          self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713',
+          id: 'cf9b0c8e-a1eb-4b65-afd0-567366448713',
+          uuid: 'cf9b0c8e-a1eb-4b65-afd0-567366448713',
+          type: 'bitstream',
+          name: 'test_word.docx',
+          metadata: [
+            {
+              key: 'dc.title',
+              language: null,
+              value: 'test_word.docx'
+            }
+          ]
+        },
+        {
+          sizeBytes: 31302,
+          content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28/content',
+          format: Observable.of({
+            self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4',
+            requestPending: false,
+            responsePending: false,
+            isSuccessful: true,
+            errorMessage: '',
+            statusCode: '202',
+            pageInfo: {},
+            payload: {
+              shortDescription: 'Adobe PDF',
+              description: 'Adobe Portable Document Format',
+              mimetype: 'application/pdf',
+              supportLevel: 0,
+              internal: false,
+              extensions: null,
+              self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4'
+            }
+          }),
+          bundleName: 'ORIGINAL',
+          self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28',
+          id: '99b00f3c-1cc6-4689-8158-91965bee6b28',
+          uuid: '99b00f3c-1cc6-4689-8158-91965bee6b28',
+          type: 'bitstream',
+          name: 'test_pdf.pdf',
+          metadata: [
+            {
+              key: 'dc.title',
+              language: null,
+              value: 'test_pdf.pdf'
+            }
+          ]
+        }
+      ]
+    }
   }),
   self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357',
   id: '0ec7ff22-f211-40ab-a69e-c819b0b1f357',
diff --git a/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts b/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts
index d52036b5dc5a648574c6d3f8edbbc43cdec96535..59df86fdffd4ad90ec224aac0dc99c1f5cccd924 100644
--- a/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts
+++ b/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts
@@ -1,5 +1,6 @@
 import { Component, Inject } from '@angular/core';
 import { ListableObject } from '../listable-object.model';
+import { hasValue } from '../../../empty.util';
 
 @Component({
   selector: 'ds-abstract-object-element',
@@ -10,4 +11,8 @@ export class AbstractListableElementComponent <T extends ListableObject> {
   public constructor(@Inject('objectElementProvider') public listableObject: ListableObject) {
     this.object = listableObject as T;
   }
+
+  hasValue(data) {
+    return hasValue(data);
+  }
 }
diff --git a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html
index ee1b9c42399e301bc9173e9e33602d2af0e4623e..728dba754968a2b678f65df86cc27ec59e58783b 100644
--- a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html
+++ b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html
@@ -12,7 +12,7 @@
             <span *ngFor="let authorMd of object.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']); let last=last;">{{authorMd.value}}
                 <span *ngIf="!last">; </span>
             </span>
-          <span *ngIf="object.findMetadata('dc.date.issued')" class="item-date">{{object.findMetadata("dc.date.issued")}}</span>
+          <span *ngIf="hasValue(object.findMetadata('dc.date.issued'))" class="item-date">{{object.findMetadata("dc.date.issued")}}</span>
         </p>
       </ds-truncatable-part>
 
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html
index 1cf14587ad4d442a7e28c97691e4c6c5d7c38e86..1e4f6f3c647f47abd0dc6c1abf0dd6ed751adf7c 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html
@@ -13,7 +13,7 @@
             <p *ngIf="dso.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0"
                class="item-authors card-text text-muted">
                 <ds-truncatable-part [fixedHeight]="true" [id]="dso.id" [minLines]="1">
-                    <span *ngIf="dso.findMetadata('dc.date.issued').length > 0" class="item-date">{{dso.findMetadata("dc.date.issued")}}</span>
+                    <span *ngIf="hasValue(dso.findMetadata('dc.date.issued'))" class="item-date">{{dso.findMetadata("dc.date.issued")}}</span>
                     <span *ngFor="let authorMd of dso.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']);">,
                         <span [innerHTML]="authorMd.value"></span>
                     </span>
diff --git a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts
index e6217eb0bbf470fb296901efd57f36e1859e2061..5ab9f472b40081223b189afd1dcc17aea9f52824 100644
--- a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts
@@ -3,7 +3,7 @@ import { Component, Inject } from '@angular/core';
 import { SearchResult } from '../../../+search-page/search-result.model';
 import { DSpaceObject } from '../../../core/shared/dspace-object.model';
 import { Metadatum } from '../../../core/shared/metadatum.model';
-import { isEmpty, hasNoValue } from '../../empty.util';
+import { isEmpty, hasNoValue, hasValue } from '../../empty.util';
 import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
 import { ListableObject } from '../../object-collection/shared/listable-object.model';
 import { TruncatableService } from '../../truncatable/truncatable.service';
@@ -60,4 +60,5 @@ export class SearchResultGridElementComponent<T extends SearchResult<K>, K exten
   isCollapsed(): Observable<boolean> {
     return this.truncatableService.isCollapsed(this.dso.id);
   }
+
 }
diff --git a/src/app/shared/object-list/item-list-element/item-list-element.component.html b/src/app/shared/object-list/item-list-element/item-list-element.component.html
index 28b83b40009a4caf455b8545ea000e8eb0ecb1b8..711ce1903755f73ba0c72d46545ecdb517af0e9d 100644
--- a/src/app/shared/object-list/item-list-element/item-list-element.component.html
+++ b/src/app/shared/object-list/item-list-element/item-list-element.component.html
@@ -11,8 +11,8 @@
                 <span *ngIf="!last">; </span>
             </span>
         </span>
-        (<span *ngIf="object.findMetadata('dc.publisher')" class="item-list-publisher">{{object.findMetadata("dc.publisher")}}, </span><span
-              *ngIf="object.findMetadata('dc.date.issued')" class="item-list-date">{{object.findMetadata("dc.date.issued")}}</span>)
+        (<span *ngIf="hasValue(object.findMetadata('dc.publisher'))" class="item-list-publisher">{{object.findMetadata("dc.publisher")}}, </span><span
+              *ngIf="hasValue(object.findMetadata('dc.date.issued'))" class="item-list-date">{{object.findMetadata("dc.date.issued")}}</span>)
       </span>
     </ds-truncatable-part>
     <ds-truncatable-part [id]="object.id" [minLines]="3">
diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html
index b8f3197a7c719d172fb9aaa24f153758af4a54b2..e1f559dd66cfd6a769fc2d2b60859b50d10f7461 100644
--- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html
+++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html
@@ -6,7 +6,7 @@
     <ds-truncatable-part [id]="dso.id" [minLines]="1">
             (<span *ngIf="dso.findMetadata('dc.publisher')" class="item-list-publisher"
                    [innerHTML]="getFirstValue('dc.publisher')">, </span><span
-            *ngIf="dso.findMetadata('dc.date.issued')" class="item-list-date"
+            *ngIf="hasValue(dso.findMetadata('dc.date.issued'))" class="item-list-date"
             [innerHTML]="getFirstValue('dc.date.issued')"></span>)
             <span *ngIf="dso.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0"
                   class="item-list-authors">