diff --git a/src/common/lspLanguageFeatures.ts b/src/common/lspLanguageFeatures.ts
index 93ecf4bd..2e33cafa 100644
--- a/src/common/lspLanguageFeatures.ts
+++ b/src/common/lspLanguageFeatures.ts
@@ -902,3 +902,57 @@ export class DocumentColorAdapter<T extends ILanguageWorkerWithDocumentColors>
 }
 
 //#endregion
+
+//#region FoldingRangeAdapter
+
+export interface ILanguageWorkerWithFoldingRanges {
+	getFoldingRanges(uri: string, context?: { rangeLimit?: number }): Promise<lsTypes.FoldingRange[]>;
+}
+
+export class FoldingRangeAdapter<T extends ILanguageWorkerWithFoldingRanges>
+	implements languages.FoldingRangeProvider
+{
+	constructor(private _worker: WorkerAccessor<T>) {}
+
+	public provideFoldingRanges(
+		model: editor.IReadOnlyModel,
+		context: languages.FoldingContext,
+		token: CancellationToken
+	): Promise<languages.FoldingRange[] | undefined> {
+		const resource = model.uri;
+
+		return this._worker(resource)
+			.then((worker) => worker.getFoldingRanges(resource.toString(), context))
+			.then((ranges) => {
+				if (!ranges) {
+					return;
+				}
+				return ranges.map((range) => {
+					const result: languages.FoldingRange = {
+						start: range.startLine + 1,
+						end: range.endLine + 1
+					};
+					if (typeof range.kind !== 'undefined') {
+						result.kind = toFoldingRangeKind(<lsTypes.FoldingRangeKind>range.kind);
+					}
+					return result;
+				});
+			});
+	}
+}
+
+function toFoldingRangeKind(
+	kind: lsTypes.FoldingRangeKind
+): languages.FoldingRangeKind | undefined {
+	switch (kind) {
+		case lsTypes.FoldingRangeKind.Comment:
+			return languages.FoldingRangeKind.Comment;
+		case lsTypes.FoldingRangeKind.Imports:
+			return languages.FoldingRangeKind.Imports;
+		case lsTypes.FoldingRangeKind.Region:
+			return languages.FoldingRangeKind.Region;
+	}
+	return void 0;
+}
+
+//#endregion
diff --git a/src/css/cssMode.ts b/src/css/cssMode.ts
index 23b46e37..d4a1b288 100644
--- a/src/css/cssMode.ts
+++ b/src/css/cssMode.ts
@@ -87,7 +87,7 @@ export function setupMode(defaults: LanguageServiceDefaults): IDisposable {
 			providers.push(
 				languages.registerFoldingRangeProvider(
 					languageId,
-					new languageFeatures.FoldingRangeAdapter(worker)
+					new languageFeatures.CSSFoldingRangeAdapter(worker)
 				)
 			);
 		}
diff --git a/src/css/languageFeatures.ts b/src/css/languageFeatures.ts
index 5935cc2b..34bdccf2 100644
--- a/src/css/languageFeatures.ts
+++ b/src/css/languageFeatures.ts
@@ -18,7 +18,8 @@ import {
 	ReferenceAdapter,
 	RenameAdapter,
 	DocumentSymbolAdapter,
-	DocumentColorAdapter
+	DocumentColorAdapter,
+	FoldingRangeAdapter
 } from '../common/lspLanguageFeatures';
 
 export interface WorkerAccessor {
@@ -51,49 +52,7 @@ export class CSSDocumentSymbolAdapter extends DocumentSymbolAdapter<CSSWorker> {
 
 export class CSSDocumentColorAdapter extends DocumentColorAdapter<CSSWorker> {}
 
-export class FoldingRangeAdapter implements languages.FoldingRangeProvider {
-	constructor(private _worker: WorkerAccessor) {}
-
-	public provideFoldingRanges(
-		model: editor.IReadOnlyModel,
-		context: languages.FoldingContext,
-		token: CancellationToken
-	): Promise<languages.FoldingRange[] | undefined> {
-		const resource = model.uri;
-
-		return this._worker(resource)
-			.then((worker) => worker.getFoldingRanges(resource.toString(), context))
-			.then((ranges) => {
-				if (!ranges) {
-					return;
-				}
-				return ranges.map((range) => {
-					const result: languages.FoldingRange = {
-						start: range.startLine + 1,
-						end: range.endLine + 1
-					};
-					if (typeof range.kind !== 'undefined') {
-						result.kind = toFoldingRangeKind(<lsTypes.FoldingRangeKind>range.kind);
-					}
-					return result;
-				});
-			});
-	}
-}
-
-function toFoldingRangeKind(
-	kind: lsTypes.FoldingRangeKind
-): languages.FoldingRangeKind | undefined {
-	switch (kind) {
-		case lsTypes.FoldingRangeKind.Comment:
-			return languages.FoldingRangeKind.Comment;
-		case lsTypes.FoldingRangeKind.Imports:
-			return languages.FoldingRangeKind.Imports;
-		case lsTypes.FoldingRangeKind.Region:
-			return languages.FoldingRangeKind.Region;
-	}
-	return void 0;
-}
+export class CSSFoldingRangeAdapter extends FoldingRangeAdapter<CSSWorker> {}
 
 export class SelectionRangeAdapter implements languages.SelectionRangeProvider {
 	constructor(private _worker: WorkerAccessor) {}
diff --git a/src/html/htmlMode.ts b/src/html/htmlMode.ts
index 705abd0f..ecc8d1ce 100644
--- a/src/html/htmlMode.ts
+++ b/src/html/htmlMode.ts
@@ -32,7 +32,7 @@ export function setupMode1(defaults: LanguageServiceDefaults): void {
 	languages.registerLinkProvider(languageId, new languageFeatures.HTMLDocumentLinkAdapter(worker));
 	languages.registerFoldingRangeProvider(
 		languageId,
-		new languageFeatures.FoldingRangeAdapter(worker)
+		new languageFeatures.HTMLFoldingRangeAdapter(worker)
 	);
 	languages.registerDocumentSymbolProvider(
 		languageId,
@@ -119,7 +119,7 @@ export function setupMode(defaults: LanguageServiceDefaults): IDisposable {
 			providers.push(
 				languages.registerFoldingRangeProvider(
 					languageId,
-					new languageFeatures.FoldingRangeAdapter(worker)
+					new languageFeatures.HTMLFoldingRangeAdapter(worker)
 				)
 			);
 		}
diff --git a/src/html/languageFeatures.ts b/src/html/languageFeatures.ts
index 404714bc..fb9a8226 100644
--- a/src/html/languageFeatures.ts
+++ b/src/html/languageFeatures.ts
@@ -16,7 +16,8 @@ import {
 	DocumentSymbolAdapter,
 	DocumentLinkAdapter,
 	DocumentFormattingEditProvider,
-	DocumentRangeFormattingEditProvider
+	DocumentRangeFormattingEditProvider,
+	FoldingRangeAdapter
 } from '../common/lspLanguageFeatures';
 
 export interface WorkerAccessor {
@@ -43,49 +44,7 @@ export class HTMLDocumentFormattingEditProvider extends DocumentFormattingEditPr
 
 export class HTMLDocumentRangeFormattingEditProvider extends DocumentRangeFormattingEditProvider<HTMLWorker> {}
 
-export class FoldingRangeAdapter implements languages.FoldingRangeProvider {
-	constructor(private _worker: WorkerAccessor) {}
-
-	public provideFoldingRanges(
-		model: editor.IReadOnlyModel,
-		context: languages.FoldingContext,
-		token: CancellationToken
-	): Promise<languages.FoldingRange[] | undefined> {
-		const resource = model.uri;
-
-		return this._worker(resource)
-			.then((worker) => worker.getFoldingRanges(resource.toString(), context))
-			.then((ranges) => {
-				if (!ranges) {
-					return;
-				}
-				return ranges.map((range) => {
-					const result: languages.FoldingRange = {
-						start: range.startLine + 1,
-						end: range.endLine + 1
-					};
-					if (typeof range.kind !== 'undefined') {
-						result.kind = toFoldingRangeKind(<lsTypes.FoldingRangeKind>range.kind);
-					}
-					return result;
-				});
-			});
-	}
-}
-
-function toFoldingRangeKind(
-	kind: lsTypes.FoldingRangeKind
-): languages.FoldingRangeKind | undefined {
-	switch (kind) {
-		case lsTypes.FoldingRangeKind.Comment:
-			return languages.FoldingRangeKind.Comment;
-		case lsTypes.FoldingRangeKind.Imports:
-			return languages.FoldingRangeKind.Imports;
-		case lsTypes.FoldingRangeKind.Region:
-			return languages.FoldingRangeKind.Region;
-	}
-	return void 0;
-}
+export class HTMLFoldingRangeAdapter extends FoldingRangeAdapter<HTMLWorker> {}
 
 export class SelectionRangeAdapter implements languages.SelectionRangeProvider {
 	constructor(private _worker: WorkerAccessor) {}
diff --git a/src/json/jsonMode.ts b/src/json/jsonMode.ts
index 875056ed..c45cd11c 100644
--- a/src/json/jsonMode.ts
+++ b/src/json/jsonMode.ts
@@ -78,7 +78,7 @@ export function setupMode(defaults: LanguageServiceDefaults): IDisposable {
 			providers.push(
 				languages.registerFoldingRangeProvider(
 					languageId,
-					new languageFeatures.FoldingRangeAdapter(worker)
+					new languageFeatures.JSONFoldingRangeAdapter(worker)
 				)
 			);
 		}
diff --git a/src/json/languageFeatures.ts b/src/json/languageFeatures.ts
index 4d3c3721..e0e4f508 100644
--- a/src/json/languageFeatures.ts
+++ b/src/json/languageFeatures.ts
@@ -16,7 +16,8 @@ import {
 	DocumentSymbolAdapter,
 	DocumentFormattingEditProvider,
 	DocumentRangeFormattingEditProvider,
-	DocumentColorAdapter
+	DocumentColorAdapter,
+	FoldingRangeAdapter
 } from '../common/lspLanguageFeatures';
 
 export interface WorkerAccessor {
@@ -62,49 +63,7 @@ export class JSONDocumentRangeFormattingEditProvider extends DocumentRangeFormat
 
 export class JSONDocumentColorAdapter extends DocumentColorAdapter<JSONWorker> {}
 
-export class FoldingRangeAdapter implements languages.FoldingRangeProvider {
-	constructor(private _worker: WorkerAccessor) {}
-
-	public provideFoldingRanges(
-		model: editor.IReadOnlyModel,
-		context: languages.FoldingContext,
-		token: CancellationToken
-	): Promise<languages.FoldingRange[] | undefined> {
-		const resource = model.uri;
-
-		return this._worker(resource)
-			.then((worker) => worker.getFoldingRanges(resource.toString(), context))
-			.then((ranges) => {
-				if (!ranges) {
-					return;
-				}
-				return ranges.map((range) => {
-					const result: languages.FoldingRange = {
-						start: range.startLine + 1,
-						end: range.endLine + 1
-					};
-					if (typeof range.kind !== 'undefined') {
-						result.kind = toFoldingRangeKind(<lsTypes.FoldingRangeKind>range.kind);
-					}
-					return result;
-				});
-			});
-	}
-}
-
-function toFoldingRangeKind(
-	kind: lsTypes.FoldingRangeKind
-): languages.FoldingRangeKind | undefined {
-	switch (kind) {
-		case lsTypes.FoldingRangeKind.Comment:
-			return languages.FoldingRangeKind.Comment;
-		case lsTypes.FoldingRangeKind.Imports:
-			return languages.FoldingRangeKind.Imports;
-		case lsTypes.FoldingRangeKind.Region:
-			return languages.FoldingRangeKind.Region;
-	}
-	return void 0;
-}
+export class JSONFoldingRangeAdapter extends FoldingRangeAdapter<JSONWorker> {}
 
 export class SelectionRangeAdapter implements languages.SelectionRangeProvider {
 	constructor(private _worker: WorkerAccessor) {}